क्या map()
सूची समझ या इसके विपरीत का उपयोग करने को प्राथमिकता देना है ? क्या उनमें से कोई भी आमतौर पर अधिक कुशल है या आम तौर पर अन्य की तुलना में अधिक पायथोनिक माना जाता है?
क्या map()
सूची समझ या इसके विपरीत का उपयोग करने को प्राथमिकता देना है ? क्या उनमें से कोई भी आमतौर पर अधिक कुशल है या आम तौर पर अन्य की तुलना में अधिक पायथोनिक माना जाता है?
जवाबों:
map
कुछ मामलों में सूक्ष्म रूप से तेज हो सकता है (जब आप उद्देश्य के लिए एक लंबोदा नहीं बना रहे हैं, लेकिन नक्शे और एक सूची में समान फ़ंक्शन का उपयोग कर रहे हैं)। सूची की समझ अन्य मामलों में तेज हो सकती है और अधिकांश (सभी नहीं) पाइथोनिस्टस उन्हें अधिक प्रत्यक्ष और स्पष्ट मानते हैं।
वास्तव में एक ही फ़ंक्शन का उपयोग करते समय मानचित्र की छोटी गति लाभ का एक उदाहरण:
$ python -mtimeit -s'xs=range(10)' 'map(hex, xs)'
100000 loops, best of 3: 4.86 usec per loop
$ python -mtimeit -s'xs=range(10)' '[hex(x) for x in xs]'
100000 loops, best of 3: 5.58 usec per loop
प्रदर्शन की तुलना पूरी तरह से विपरीत हो जाती है, जब मानचित्र को लंबोदर की आवश्यकता होती है, इसका एक उदाहरण:
$ python -mtimeit -s'xs=range(10)' 'map(lambda x: x+2, xs)'
100000 loops, best of 3: 4.24 usec per loop
$ python -mtimeit -s'xs=range(10)' '[x+2 for x in xs]'
100000 loops, best of 3: 2.32 usec per loop
map(operator.attrgetter('foo'), objs)
से पढ़ने में आसान [o.foo for o in objs]
!
o
यहां, और आपके उदाहरण बताते हैं कि क्यों।
str()
उदाहरण है, हालांकि उनका उदाहरण है।
मामले
map
, हालांकि इसे 'अनीफैथोनिक' माना जाता है। उदाहरण के लिए, map(sum, myLists)
की तुलना में अधिक सुरुचिपूर्ण / कविता है [sum(x) for x in myLists]
। आपको डमी वैरिएबल (जैसे sum(x) for x...
या sum(_) for _...
या sum(readableName) for readableName...
) जो आपको दो बार टाइप करना है, केवल इट्रेट करने के लिए नहीं होने की लालित्य प्राप्त करता है । एक ही तर्क मॉड्यूल के लिए filter
और reduce
कुछ भी रखता है itertools
: यदि आपके पास पहले से ही कोई फ़ंक्शन है, तो आप आगे बढ़ सकते हैं और कुछ कार्यात्मक प्रोग्रामिंग कर सकते हैं। यह कुछ स्थितियों में पठनीयता हासिल करता है, और इसे दूसरों में खो देता है (जैसे नौसिखिए प्रोग्रामर, कई तर्क) ... लेकिन आपके कोड की पठनीयता वैसे भी आपकी टिप्पणियों पर निर्भर करती है।map
कार्यात्मक प्रोग्रामिंग करते समय एक शुद्ध सार फ़ंक्शन के रूप में फ़ंक्शन का उपयोग करना चाह सकते हैं , जहां आप मैपिंग कर रहे हैं map
, या करी कर रहे हैं map
, या अन्यथा map
फ़ंक्शन के बारे में बात करने से लाभ उठा सकते हैं । उदाहरण के लिए हास्केल में, एक फ़ंक्शनल इंटरफ़ेस जिसे fmap
किसी भी डेटा संरचना पर मैपिंग को सामान्यीकृत किया जाता है। यह अजगर में बहुत ही असामान्य है क्योंकि अजगर व्याकरण आपको पुनरावृत्ति के बारे में बात करने के लिए जनरेटर-शैली का उपयोग करने के लिए मजबूर करता है; आप इसे आसानी से सामान्य नहीं कर सकते। (यह कभी-कभी अच्छा होता है और कभी-कभी बुरा होता है।) आप शायद दुर्लभ अजगर उदाहरणों के साथ आ सकते हैं, जहां map(f, *lists)
करना उचित है। निकटतम उदाहरण मैं साथ आ सकता हूं sumEach = partial(map,sum)
, जो कि एक-लाइनर है जो बहुत ही समान है:def sumEach(myLists):
return [sum(_) for _ in myLists]
for
-लूप का उपयोग करना : आप निश्चित रूप से सिर्फ फॉर-लूप का उपयोग कर सकते हैं। हालांकि एक कार्यात्मक-प्रोग्रामिंग दृष्टिकोण से उतना सुंदर नहीं है, कभी-कभी गैर-स्थानीय चर, अनिवार्य प्रोग्रामिंग भाषाओं जैसे अजगर में कोड को स्पष्ट कर देते हैं, क्योंकि लोग उस तरह से कोड पढ़ने के लिए उपयोग किए जाते हैं। फ़ोर-लूप भी हैं, आम तौर पर, सबसे अधिक कुशल जब आप किसी भी जटिल ऑपरेशन को कर रहे होते हैं जो सूची-बोध और मानचित्र जैसी सूची का निर्माण नहीं कर रहे होते हैं (जैसे संक्षेप में, या एक पेड़ बनाने के लिए, आदि) - कम से कम स्मृति के संदर्भ में कुशल (समय के संदर्भ में जरूरी नहीं, जहां मैं सबसे खराब कारक की उम्मीद करूं, कुछ दुर्लभ रोग-कचरा-संग्रह हिचकी को रोकना)।"Pythonism"
मैं "पाइथोनिक" शब्द को नापसंद करता हूं क्योंकि मुझे नहीं लगता कि पाइथोनिक मेरी आंखों में हमेशा सुरुचिपूर्ण है। फिर भी, map
और filter
(इसी तरह के उपयोगी itertools
मॉड्यूल की तरह) कार्यों को शैली के संदर्भ में संभवतः अनैफोनिक माना जाता है।
आलस्य
दक्षता के संदर्भ में, अधिकांश कार्यात्मक प्रोग्रामिंग निर्माणों की तरह, MAP CAN BE LAZY , और वास्तव में अजगर में आलसी है। इसका मतलब है कि आप ऐसा कर सकते हैं ( python3 में ) और आपका कंप्यूटर मेमोरी से बाहर नहीं चलेगा और आपके सभी सहेजे न गए डेटा को खो देगा:
>>> map(str, range(10**100))
<map object at 0x2201d50>
एक सूची समझने की कोशिश करें:
>>> [str(n) for n in range(10**100)]
# DO NOT TRY THIS AT HOME OR YOU WILL BE SAD #
ध्यान दें कि सूची की समझ भी स्वाभाविक रूप से आलसी है, लेकिन अजगर ने उन्हें गैर-आलसी के रूप में लागू करने के लिए चुना है । फिर भी, अजगर जनरेटर के रूप में आलसी सूची समझ का समर्थन करता है, जो निम्नानुसार है:
>>> (str(n) for n in range(10**100))
<generator object <genexpr> at 0xacbdef>
आप मूल रूप से [...]
वाक्य रचनाकार को सूची निर्माणकर्ता की तरह जनरेटर अभिव्यक्ति में पास करने के बारे में सोच सकते हैं , जैसे list(x for x in range(5))
।
संक्षिप्त संक्षिप्त उदाहरण
from operator import neg
print({x:x**2 for x in map(neg,range(5))})
print({x:x**2 for x in [-y for y in range(5)]})
print({x:x**2 for x in (-y for y in range(5))})
सूची की समझ गैर-आलसी है, इसलिए अधिक मेमोरी की आवश्यकता हो सकती है (जब तक कि आप जनरेटर की समझ का उपयोग न करें)। वर्ग कोष्ठक [...]
अक्सर चीजों को स्पष्ट करते हैं, खासकर जब कोष्ठक की गड़बड़ी में। दूसरी ओर, कभी-कभी आप अंत में टाइपिंग की तरह क्रिया करते हैं [x for x in...
। जब तक आप अपने पुनरावृत्तियों को छोटा रखते हैं, तब तक सूची बोध सामान्य रूप से स्पष्ट हो जाता है यदि आप अपने कोड को इंडेंट नहीं करते हैं। लेकिन आप हमेशा अपने कोड को इंडेंट कर सकते हैं।
print(
{x:x**2 for x in (-y for y in range(5))}
)
या चीजों को तोड़ना:
rangeNeg5 = (-y for y in range(5))
print(
{x:x**2 for x in rangeNeg5}
)
पायथन 3 के लिए दक्षता तुलना
map
अब आलसी है:
% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=map(f,xs)'
1000000 loops, best of 3: 0.336 usec per loop ^^^^^^^^^
इसलिए यदि आप अपने सभी डेटा का उपयोग नहीं कर रहे हैं, या समय से पहले नहीं जानते हैं कि आपको कितने डेटा की आवश्यकता है, तो map
python3 में (और python2 या python3 में जनरेटर के भाव) अंतिम मूल्यों की आवश्यकता होने तक उनके मूल्यों की गणना करने से बचें। आमतौर पर यह आमतौर पर किसी भी उपरि का उपयोग करने से आगे निकल जाएगा map
। नकारात्मक पक्ष यह है कि यह सबसे कार्यात्मक भाषाओं के विपरीत अजगर में बहुत सीमित है: आपको यह लाभ केवल तभी मिलता है जब आप अपने डेटा को बाएं से दाएं "क्रम में" तक पहुंचते हैं, क्योंकि अजगर जनरेटर के अभिव्यक्तियों का केवल आदेश का मूल्यांकन किया जा सकता है x[0], x[1], x[2], ...
।
हालाँकि हम कहते हैं कि हमारे पास एक पूर्व-निर्मित कार्य है f
जिसे हम करना चाहते हैं map
, और हम map
तुरंत के साथ मूल्यांकन को मजबूर करके आलस्य को अनदेखा करते हैं list(...)
। हम कुछ बहुत ही रोचक परिणाम प्राप्त करते हैं:
% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=list(map(f,xs))'
10000 loops, best of 3: 165/124/135 usec per loop ^^^^^^^^^^^^^^^
for list(<map object>)
% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=[f(x) for x in xs]'
10000 loops, best of 3: 181/118/123 usec per loop ^^^^^^^^^^^^^^^^^^
for list(<generator>), probably optimized
% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=list(f(x) for x in xs)'
1000 loops, best of 3: 215/150/150 usec per loop ^^^^^^^^^^^^^^^^^^^^^^
for list(<generator>)
परिणाम एएए / बीबीबी / सीसीसी के रूप में हैं, जहां ए को एक सर्पा-2010 इंटेल वर्कस्टेशन पर पायथन 3 के साथ प्रदर्शन किया गया था। और, और बी और सी को एक ए -2013 एएमडी वर्कस्टेशन के साथ अजगर 3.2.1 के साथ प्रदर्शन किया गया था। बेहद अलग हार्डवेयर के साथ। परिणाम यह प्रतीत होता है कि प्रदर्शन में मानचित्र और सूची की समझ तुलनीय है, जो अन्य यादृच्छिक कारकों से सबसे अधिक प्रभावित होता है। केवल एक चीज जो हम बता सकते हैं, वह यह है कि अजीब तरह से, जबकि हम उम्मीद करते हैं कि सूची [...]
अभिव्यक्तियाँ जनरेटर के अभिव्यक्तियों की तुलना में बेहतर प्रदर्शन करती हैं (...)
, map
यह भी अधिक कुशल है कि जनरेटर अभिव्यक्ति (फिर से यह मानकर कि सभी मूल्यों का मूल्यांकन / उपयोग किया जाता है)।
यह महसूस करना महत्वपूर्ण है कि ये परीक्षण एक बहुत ही सरल कार्य (पहचान समारोह) मानते हैं; हालांकि यह ठीक है क्योंकि यदि फ़ंक्शन जटिल था, तो कार्यक्रम में अन्य कारकों की तुलना में प्रदर्शन ओवरहेड नगण्य होगा। (यह अभी भी अन्य सरल चीजों के साथ परीक्षण करने के लिए दिलचस्प हो सकता है f=lambda x:x+x
)
यदि आप अजगर विधानसभा को पढ़ने में कुशल हैं, तो आप dis
मॉड्यूल का उपयोग करके देख सकते हैं कि क्या वास्तव में पर्दे के पीछे चल रहा है:
>>> listComp = compile('[f(x) for x in xs]', 'listComp', 'eval')
>>> dis.dis(listComp)
1 0 LOAD_CONST 0 (<code object <listcomp> at 0x2511a48, file "listComp", line 1>)
3 MAKE_FUNCTION 0
6 LOAD_NAME 0 (xs)
9 GET_ITER
10 CALL_FUNCTION 1
13 RETURN_VALUE
>>> listComp.co_consts
(<code object <listcomp> at 0x2511a48, file "listComp", line 1>,)
>>> dis.dis(listComp.co_consts[0])
1 0 BUILD_LIST 0
3 LOAD_FAST 0 (.0)
>> 6 FOR_ITER 18 (to 27)
9 STORE_FAST 1 (x)
12 LOAD_GLOBAL 0 (f)
15 LOAD_FAST 1 (x)
18 CALL_FUNCTION 1
21 LIST_APPEND 2
24 JUMP_ABSOLUTE 6
>> 27 RETURN_VALUE
>>> listComp2 = compile('list(f(x) for x in xs)', 'listComp2', 'eval')
>>> dis.dis(listComp2)
1 0 LOAD_NAME 0 (list)
3 LOAD_CONST 0 (<code object <genexpr> at 0x255bc68, file "listComp2", line 1>)
6 MAKE_FUNCTION 0
9 LOAD_NAME 1 (xs)
12 GET_ITER
13 CALL_FUNCTION 1
16 CALL_FUNCTION 1
19 RETURN_VALUE
>>> listComp2.co_consts
(<code object <genexpr> at 0x255bc68, file "listComp2", line 1>,)
>>> dis.dis(listComp2.co_consts[0])
1 0 LOAD_FAST 0 (.0)
>> 3 FOR_ITER 17 (to 23)
6 STORE_FAST 1 (x)
9 LOAD_GLOBAL 0 (f)
12 LOAD_FAST 1 (x)
15 CALL_FUNCTION 1
18 YIELD_VALUE
19 POP_TOP
20 JUMP_ABSOLUTE 3
>> 23 LOAD_CONST 0 (None)
26 RETURN_VALUE
>>> evalledMap = compile('list(map(f,xs))', 'evalledMap', 'eval')
>>> dis.dis(evalledMap)
1 0 LOAD_NAME 0 (list)
3 LOAD_NAME 1 (map)
6 LOAD_NAME 2 (f)
9 LOAD_NAME 3 (xs)
12 CALL_FUNCTION 2
15 CALL_FUNCTION 1
18 RETURN_VALUE
ऐसा लगता है कि [...]
सिंटैक्स का उपयोग करना बेहतर है list(...)
। अफसोस की बात है कि map
क्लास डिसाइड करने के लिए थोड़ा अपारदर्शी है, लेकिन हम अपनी गति परीक्षण के कारण बना सकते हैं।
map
और filter
मानक पुस्तकालय के साथ itertools
स्वाभाविक रूप से खराब शैली है। जब तक जीवीआर वास्तव में यह नहीं कहता कि वे या तो एक भयानक गलती थे या केवल प्रदर्शन के लिए, एकमात्र प्राकृतिक निष्कर्ष यदि "पाइथोनेसिस" कहता है कि इसे बेवकूफी के रूप में भूलना है ;-)
map
/ filter
पायथन 3 के लिए एक महान विचार था , और केवल अन्य पायथनो द्वारा विद्रोह ने उन्हें अंतर्निहित नेमस्पेस (जबकि reduce
स्थानांतरित कर दिया गया था functools
) में रखा। मैं व्यक्तिगत रूप से असहमत हूं ( map
और filter
पूर्वनिर्धारित, विशेष रूप से निर्मित-कार्यों के साथ ठीक हैं, यदि lambda
आवश्यक हो तो कभी भी उनका उपयोग न करें ), लेकिन जीवीआर ने मूल रूप से उन्हें वर्षों तक पाइथोनिक नहीं कहा है।
itertools
? इस जवाब से मैं जो अंश उद्धृत करता हूं, वह मुख्य दावा है कि मुझे परेशान करता है। मैं नहीं पता है उनके आदर्श दुनिया में चाहे, map
और filter
करने के लिए कदम होगा itertools
(या functools
) या पूरी तरह से जाना है, लेकिन जो भी मामला है, एक बार एक का कहना है कि itertools
अपनी संपूर्णता में unPythonic है, तो मैं सच में नहीं पता है कि "pythonic" है मतलब है, लेकिन मुझे नहीं लगता कि यह "जीवीआर लोगों को उपयोग करने की सिफारिश करता है" के समान कुछ भी हो सकता है।
map
/ filter
, नहीं itertools
। कार्यात्मक प्रोग्रामिंग पूरी तरह से pythonic है ( itertools
, functools
और operator
सब को ध्यान में कार्यात्मक प्रोग्रामिंग के साथ विशेष रूप से डिजाइन किए गए थे, और मैं अजगर सब समय में कार्यात्मक मुहावरे का उपयोग करें), और itertools
है विशेष रूप से सुविधाओं है कि एक दर्द अपने आप को लागू करने के लिए किया जाएगा प्रदान करता है, यह map
और filter
जनरेटर भाव के साथ किया जा रहा अनावश्यक जिससे गुइडो को उनसे नफरत हो गई। itertools
हमेशा ठीक रहा है।
map
और filter
सूची comprehensions के बजाय।एक उद्देश्य यह है कि आपको उन्हें "पाइथोनिक" नहीं होने के बावजूद भी क्यों पसंद करना चाहिए:
उन्हें तर्क के रूप में कार्यों / लंबोधों की आवश्यकता होती है, जो एक नए दायरे का परिचय देते हैं ।
मैंने एक से अधिक बार इससे काट लिया है:
for x, y in somePoints:
# (several lines of code here)
squared = [x ** 2 for x in numbers]
# Oops, x was silently overwritten!
लेकिन अगर इसके बजाय मैंने कहा था:
for x, y in somePoints:
# (several lines of code here)
squared = map(lambda x: x ** 2, numbers)
तब सब ठीक हो जाता।
आप कह सकते हैं कि मैं समान दायरे में समान चर नाम का उपयोग करने के लिए मूर्खतापूर्ण था।
मैं नहीं था। मूल रूप से कोड ठीक था - दोनों x
एक ही दायरे में नहीं थे।
यह आंतरिक ब्लॉक को कोड के एक अलग खंड में स्थानांतरित करने के बाद ही समस्या आई थी (पढ़ें: रखरखाव के दौरान समस्या, विकास नहीं), और मुझे इसकी उम्मीद नहीं थी।
हां, यदि आप कभी यह गलती नहीं करते हैं , तो सूची की समझ अधिक सुरुचिपूर्ण है।
लेकिन व्यक्तिगत अनुभव से (और दूसरों को देखने से एक ही गलती होती है) मैंने देखा है कि यह पर्याप्त बार हुआ है कि मुझे लगता है कि यह दर्द के लायक नहीं है जब आपको इन बगों से गुजरना पड़ता है।
का उपयोग करें map
और filter
। वे सूक्ष्म-से-कठिन निदान गुंजाइश-संबंधी बग को रोकते हैं।
उपयोग करने पर विचार के लिए मत भूलना imap
और ifilter
(में itertools
) अगर वे अपनी स्थिति के लिए उपयुक्त हैं!
map
/ और / या पर स्विच करने का तार्किक कारण नहीं है filter
। यदि कुछ भी हो, तो आपकी समस्या से बचने के लिए सबसे सीधा और तार्किक अनुवाद map(lambda x: x ** 2, numbers)
एक जेनरेटर अभिव्यक्ति के बजाय list(x ** 2 for x in numbers)
नहीं है, जो लीक नहीं करता है, जैसा कि जेरोमेज ने पहले ही बताया है। मेहरदाद देखो, व्यक्तिगत रूप से इतना पतन मत करो, मैं यहाँ तुम्हारे तर्क से पूरी तरह असहमत हूँ।
वास्तव में, map
और सूची की समझ पायथन 3 भाषा में काफी अलग तरह से व्यवहार करती है। निम्नलिखित पायथन 3 कार्यक्रम पर एक नज़र डालें:
def square(x):
return x*x
squares = map(square, [1, 2, 3])
print(list(squares))
print(list(squares))
आप इसे दो बार "[1, 4, 9]" लाइन प्रिंट करने की उम्मीद कर सकते हैं, लेकिन इसके बजाय "[1, 4, 9]" प्रिंट करता है और उसके बाद "[]"। पहली बार जब आप squares
इसे देखते हैं तो यह तीन तत्वों के अनुक्रम के रूप में व्यवहार करता है, लेकिन दूसरी बार एक खाली के रूप में।
अजगर 2 भाषा में map
एक पुरानी पुरानी सूची देता है, जैसे सूची की समझ दोनों भाषाओं में होती है। क्रुक्स यह है कि map
पायथन 3 (और imap
पायथन 2 में) का रिटर्न मान एक सूची नहीं है - यह एक पुनरावृत्त है!
जब आप किसी सूची पर पुनरावृति करते हैं, तो इसके विपरीत एक पुनरावृति पर पुनरावृति करने पर तत्वों की खपत होती है। यही कारण है कि squares
अंतिम print(list(squares))
पंक्ति में खाली दिखता है ।
संक्षेप में:
map
एक डेटा संरचना का उत्पादन करने के लिए है, न कि एक पुनरावृत्त। लेकिन शायद आलसी पुनरावृत्तियों आलसी डेटा संरचनाओं की तुलना में आसान है। सोच के लिए भोजन। धन्यवाद @MnZrK
मुझे लगता है कि सूची की समझ आम तौर पर जो मैं करने की कोशिश कर रहा हूं उससे अधिक अभिव्यंजक हैं map
- वे दोनों इसे पूरा करते हैं, लेकिन पूर्व समझने का मानसिक भार बचाता है जो एक जटिल lambda
अभिव्यक्ति हो सकती है ।
वहाँ भी एक साक्षात्कार कहीं है (मैं इसे बंद नहीं मिल सकता है) जहां गुइडो lambda
एस सूचीबद्ध करता है और कार्यात्मक कार्यों के रूप में वह चीज़ जिसे वह पायथन में स्वीकार करने के बारे में सबसे अधिक पछतावा करता है, इसलिए आप तर्क दे सकते हैं कि वे अन-पायथोनिक हैं पुण्य से उसका।
const
C ++ में कीवर्ड इन पंक्तियों के साथ एक शानदार जीत है।
lambda
इतना लंगड़ा कर दिया गया है (कोई बयान नहीं ..) कि वे का उपयोग करना मुश्किल है और वैसे भी सीमित हैं।
यहाँ एक संभव मामला है:
map(lambda op1,op2: op1*op2, list1, list2)
बनाम:
[op1*op2 for op1,op2 in zip(list1,list2)]
मैं अनुमान लगा रहा हूं कि जिप () एक दुर्भाग्यपूर्ण और अनावश्यक ओवरहेड है जिसे आपको नक्शे के बजाय सूची समझ का उपयोग करने पर जोर देने की आवश्यकता है। बहुत अच्छा होगा यदि कोई इसे स्पष्ट करे चाहे सकारात्मक या नकारात्मक।
zip
का उपयोग करके आलसीitertools.izip
map(operator.mul, list1, list2)
। यह इन बहुत ही सरल बाईं ओर अभिव्यक्तियों पर है कि समझदारी अनाड़ी हो जाती है।
यदि आप किसी भी अतुल्यकालिक, समानांतर, या वितरित कोड को लिखने की योजना बनाते हैं, तो आप संभवतः map
एक सूची समझ से अधिक पसंद करेंगे - जैसा कि अधिकांश अतुल्यकालिक, समानांतर, या वितरित पैकेज एक map
फ़ंक्शन को ओवरहाइट अजगर को अधिभार प्रदान करते हैं map
। फिर map
अपने बाकी कोड के लिए उपयुक्त फ़ंक्शन पास करके, आपको अपने मूल सीरियल कोड को संशोधित नहीं करना पड़ सकता है ताकि इसे समानांतर (आदि) में चलाया जा सके।
इसलिए पायथन 3 के बाद से, map()
एक पुनरावृत्त व्यक्ति है, आपको यह ध्यान रखने की आवश्यकता है कि आपको क्या चाहिए: एक पुनरावृत्त या list
वस्तु।
जैसा कि @AlexMartelli ने पहले ही उल्लेख किया है , map()
यदि आप lambda
फ़ंक्शन का उपयोग नहीं करते हैं तो सूची समझ से अधिक तेज़ है ।
मैं आपको कुछ समय की तुलना प्रस्तुत करूंगा।
पायथन 3.5.2 और सीपीथॉन
मैंने बृहस्पति नोटबुक का उपयोग किया है और विशेष रूप से %timeit
अंतर्निहित जादू कमांड
मापक : s == 1000 एमएस == 1000 * 1000 = = = 1000 * 1000 * 1000 एनएस
सेट अप:
x_list = [(i, i+1, i+2, i*2, i-9) for i in range(1000)]
i_list = list(range(1000))
निर्मित समारोह:
%timeit map(sum, x_list) # creating iterator object
# Output: The slowest run took 9.91 times longer than the fastest.
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 277 ns per loop
%timeit list(map(sum, x_list)) # creating list with map
# Output: 1000 loops, best of 3: 214 µs per loop
%timeit [sum(x) for x in x_list] # creating list with list comprehension
# Output: 1000 loops, best of 3: 290 µs per loop
lambda
समारोह:
%timeit map(lambda i: i+1, i_list)
# Output: The slowest run took 8.64 times longer than the fastest.
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 325 ns per loop
%timeit list(map(lambda i: i+1, i_list))
# Output: 1000 loops, best of 3: 183 µs per loop
%timeit [i+1 for i in i_list]
# Output: 10000 loops, best of 3: 84.2 µs per loop
जनरेटर अभिव्यक्ति के रूप में ऐसी चीज भी है, PEP-0289 देखें । इसलिए मैंने सोचा कि तुलना करने के लिए इसे जोड़ना उपयोगी होगा
%timeit (sum(i) for i in x_list)
# Output: The slowest run took 6.66 times longer than the fastest.
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 495 ns per loop
%timeit list((sum(x) for x in x_list))
# Output: 1000 loops, best of 3: 319 µs per loop
%timeit (i+1 for i in i_list)
# Output: The slowest run took 6.83 times longer than the fastest.
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 506 ns per loop
%timeit list((i+1 for i in i_list))
# Output: 10000 loops, best of 3: 125 µs per loop
list
वस्तु की आवश्यकता है:सूची बोध का उपयोग करें यदि यह कस्टम फ़ंक्शन है, list(map())
तो अंतर्निहित फ़ंक्शन का उपयोग करें
list
ऑब्जेक्ट की आवश्यकता नहीं है , आपको बस पुनरावृत्ति की आवश्यकता है:हमेशा उपयोग करें map()
!
मैंने एक त्वरित परीक्षण किया, जो किसी वस्तु की विधि को लागू करने के लिए तीन तरीकों की तुलना करता है। इस मामले में, समय का अंतर, नगण्य है और सवाल में फ़ंक्शन का मामला है (देखें @ एलेक्स मार्टेली की प्रतिक्रिया )। यहाँ, मैंने निम्नलिखित विधियों को देखा:
# map_lambda
list(map(lambda x: x.add(), vals))
# map_operator
from operator import methodcaller
list(map(methodcaller("add"), vals))
# map_comprehension
[x.add() for x in vals]
मैंने सूची आकार में वृद्धि के लिए vals
दोनों पूर्णांकों (पायथन int
) और फ्लोटिंग पॉइंट नंबरों (पायथन float
) के सूचियों (संग्रह में संग्रहीत ) को देखा । निम्नलिखित डमी वर्ग DummyNum
माना जाता है:
class DummyNum(object):
"""Dummy class"""
__slots__ = 'n',
def __init__(self, n):
self.n = n
def add(self):
self.n += 5
विशेष रूप से, add
विधि। __slots__
विशेषता पायथन में एक साधारण अनुकूलन, कुल स्मृति वर्ग (विशेषताएँ) द्वारा आवश्यक परिभाषित करने के लिए स्मृति आकार को कम करने है। यहाँ परिणामी भूखंड हैं।
जैसा कि पहले कहा गया था, तकनीक का इस्तेमाल कम से कम अंतर करता है और आपको इस तरह से कोड करना चाहिए जो आपके लिए सबसे अधिक पठनीय हो, या विशेष परिस्थिति में। इस मामले में, सूची समझ ( map_comprehension
तकनीक) किसी वस्तु में दोनों प्रकार के परिवर्धन के लिए सबसे तेज़ है, विशेष रूप से छोटी सूचियों के साथ।
प्लॉट और डेटा उत्पन्न करने के लिए उपयोग किए जाने वाले स्रोत के लिए इस पास्टबिन पर जाएं ।
map
तभी तेजी से काम किया जाता है जब फ़ंक्शन को ठीक उसी तरह से बुलाया जाता है (यानी [*map(f, vals)]
बनाम [f(x) for x in vals]
)। तो list(map(methodcaller("add"), vals))
से तेज है [methodcaller("add")(x) for x in vals]
। map
लूपिंग समकक्ष एक अलग कॉलिंग विधि का उपयोग करता है जब कुछ ओवरहेड से बच सकते हैं (जैसे या लैम्ब्डा अभिव्यक्ति ओवरहेड x.add()
से बचा जाता है methodcaller
) का उपयोग तेजी से नहीं हो सकता है । इस विशिष्ट परीक्षण के मामले के लिए, [*map(DummyNum.add, vals)]
तेज होगा (क्योंकि DummyNum.add(x)
और x.add()
मूल रूप से एक ही प्रदर्शन है)।
list()
कॉल्स सूची की समझ से थोड़ी धीमी हैं। निष्पक्ष तुलना के लिए आपको लिखना होगा [*map(...)]
।
list()
कॉल ओवरहेड हो गए। उत्तरों के माध्यम से पढ़ने में अधिक समय देना चाहिए। मैं इन परीक्षणों को एक निष्पक्ष तुलना के लिए फिर से चलाऊंगा, हालांकि मतभेद नगण्य हो सकते हैं।
मेरा मानना है कि सबसे पायथोनिक तरीका एक सूची समझ का उपयोग करना है map
और इसके बजाय filter
। कारण यह है कि सूची की समझ map
और की तुलना में स्पष्ट हैं filter
।
In [1]: odd_cubes = [x ** 3 for x in range(10) if x % 2 == 1] # using a list comprehension
In [2]: odd_cubes_alt = list(map(lambda x: x ** 3, filter(lambda x: x % 2 == 1, range(10)))) # using map and filter
In [3]: odd_cubes == odd_cubes_alt
Out[3]: True
जैसा कि आप देखते हैं, एक समझ के लिए अतिरिक्त lambda
अभिव्यक्तियों की आवश्यकता नहीं होती है map
। इसके अलावा, एक समझ भी आसानी से फ़िल्टरिंग की अनुमति देती है, जबकि फ़िल्टरिंग की अनुमति देने की map
आवश्यकता होती filter
है।
मैंने @ एलेक्स-मार्टेली द्वारा कोड की कोशिश की, लेकिन कुछ विसंगतियां पाई गईं
python -mtimeit -s "xs=range(123456)" "map(hex, xs)"
1000000 loops, best of 5: 218 nsec per loop
python -mtimeit -s "xs=range(123456)" "[hex(x) for x in xs]"
10 loops, best of 5: 19.4 msec per loop
मानचित्र की समझ का उपयोग करते हुए भी बहुत बड़ी श्रेणियों के लिए मानचित्र समान समय लेता है, जैसा कि मेरे कोड से स्पष्ट है। इसलिए "अनहाइथोनिक" माने जाने के अलावा, मैंने मानचित्र के उपयोग से संबंधित किसी भी प्रदर्शन के मुद्दे का सामना नहीं किया है।
map
एक सूची मिलती है। पायथन 3 में, map
आलसी का मूल्यांकन किया जाता है, इसलिए केवल कॉलिंग map
किसी भी नई सूची तत्वों की गणना नहीं करती है, इसलिए आपको बहुत कम समय मिलता है।