पायथन 3 में सूची के बजाय मानचित्र ऑब्जेक्ट को क्यों लौटाता है?


83

मुझे पायथन 3.x की नई भाषा डिजाइन को समझने में दिलचस्पी है ।

मैं पायथन 2.7 में, फंक्शन का आनंद लेता हूं map:

Python 2.7.12
In[2]: map(lambda x: x+1, [1,2,3])
Out[2]: [2, 3, 4]

हालाँकि, पायथन में 3.x चीजें बदल गई हैं:

Python 3.5.1
In[2]: map(lambda x: x+1, [1,2,3])
Out[2]: <map at 0x4218390>

मुझे समझ में कैसे आया, लेकिन मुझे इसका संदर्भ नहीं मिला। भाषा डिजाइनरों ने यह विकल्प क्यों बनाया, जो, मेरी राय में, बहुत दर्द का परिचय देता है। क्या यह बांझ-कुश्ती डेवलपर्स को समझ की सूची से चिपके रहने के लिए था?

IMO, सूची को स्वाभाविक रूप से फ़नट्रक्टर के रूप में सोचा जा सकता है ; और मुझे इस तरह से सोचने के लिए किसी तरह से सोचा गया है:

fmap :: (a -> b) -> f a -> f b

2
तर्क समान होना चाहिए कि हम सूची बोध के बजाय जनरेटर का उपयोग क्यों करें। आलसी मूल्यांकन का उपयोग करके हमें स्मृति में बड़ी चीजों को रखने की आवश्यकता नहीं है। यहाँ दिए गए स्वीकृत उत्तर की जाँच करें: stackoverflow.com/questions/1303347/…
— Moberg

8
क्या आप बता सकते हैं कि यह आपको "दर्द का एक बड़ा कारण" क्यों लाता है?
— रेमकोगर्लिच

3
मुझे लगता है कि यह इसलिए है क्योंकि उपयोग के वर्षों में दिखाया गया कि mapपरिणाम में सबसे आम उपयोग पुनरावृत्त होते हैं। एक सूची का निर्माण जब आपको इसकी आवश्यकता नहीं है तो यह अक्षम है इसलिए देवों ने mapआलसी बनाने का फैसला किया । प्रदर्शन के लिए यहां बहुत कुछ हासिल करना है और बहुत कुछ खोना नहीं है (यदि आपको सूची की आवश्यकता है, तो बस एक के लिए पूछें ... list(map(...)))।
— 8

3
ठीक है, मुझे यह दिलचस्प लगता है कि फ़ंक्टर पैटर्न रखने और सूची के एक आलसी संस्करण की पेशकश करने के बजाय, उन्होंने किसी भी तरह एक सूची के आलसी मूल्यांकन को बाध्य करने का निर्णय लिया जब भी इसे मैप किया जाता है। मैं अपनी पसंद, आका, जेनरेटर -> मैप -> जेनरेटर या लिस्ट -> मैप -> लिस्ट (निर्णय करने के लिए मेरे पास) बनाने का
— अधिकार रखना पसंद करूंगा

4
@NoIdeaHowToFixThis, वास्तव में आप पर निर्भर है, अगर आपको पूरी सूची की आवश्यकता है, तो बस इसे एक सूची में बदल दें, नर्क के रूप में आसान
— नेटवेव

जवाबों:


37

मुझे लगता है कि कारण है कि नक्शा अभी भी मौजूद है सब पर जब जनरेटर भाव भी मौजूद हैं, है कि यह कई इटरेटर तर्क है कि सब कुछ खत्म हो लूप में चलाया और समारोह में पारित कर रहे हैं ले जा सकते हैं:

>>> list(map(min, [1,2,3,4], [0,10,0,10]))
[0,2,0,4]

ज़िप का उपयोग करने की तुलना में यह थोड़ा आसान है:

>>> list(min(x, y) for x, y in zip([1,2,3,4], [0,10,0,10]))

अन्यथा, यह केवल जनरेटर अभिव्यक्तियों पर कुछ भी नहीं जोड़ता है।


1
मुझे लगता है कि अगर हम तनाव की इच्छा को जोड़ते हैं कि सूची की समझ अधिक आकर्षक है और भाषा डिजाइनर इस बात पर जोर देना चाहते हैं कि, यह सबसे ऑन-स्पॉट जवाब है, तो मुझे लगता है। @vishes_shell किसी भी तरह भाषा डिजाइन पर पर्याप्त ध्यान केंद्रित नहीं करता है।
— NoIdeaHowToFixThis

2
पायथन 2 और 3 में अलग-अलग परिणाम उत्पन्न करता है यदि दो सूचियाँ समान लंबाई की नहीं हैं । c = list(map(max, [1,2,3,4], [0,10,0,10, 99]))अजगर 2 में और अजगर 3 में प्रयास करें
— cdarke

1
यहाँ मूल रूप से python3 से पूरी तरह से नक्शा हटाने की योजना का एक संदर्भ है: artima.com/weblogs/viewpost.jsp?thread=98196
— बर्नहार्ड

हम्म कितना अजीब है जब मैं मानचित्र को सूची में लपेटता हूं, तो मुझे 1 तत्व सूची मिलती है।
— awiebe

24

क्योंकि यह एक पुनरावृत्ति देता है, यह स्मृति में पूर्ण आकार की सूची को संग्रहीत करता है। ताकि आप आसानी से भविष्य में उस पर पुनरावृति कर सकें, जिससे स्मृति को कोई दर्द न हो। संभवतः आपको पूरी सूची की भी आवश्यकता नहीं है, लेकिन जब तक आपकी स्थिति नहीं हो जाती है, तब तक इसका हिस्सा रहें।

आप इस डॉक्स को उपयोगी पा सकते हैं , पुनरावृत्तियाँ कमाल की हैं।

डेटा की एक धारा का प्रतिनिधित्व करने वाली वस्तु। पुनरावृत्त पुनरावृत्त की __next__()विधि को कॉल करता है (या इसे अंतर्निहित फ़ंक्शन में भेज रहा है next()) धारा में क्रमिक आइटम लौटाता है। जब कोई और डेटा उपलब्ध नहीं होता है तो StopIterationइसके बजाय एक अपवाद उठाया जाता है। इस बिंदु पर, इट्रेटर ऑब्जेक्ट समाप्त हो गया है और इसकी __next__()विधि के लिए आगे कॉल StopIterationफिर से बढ़ा । Iterators के लिए आवश्यक है __iter__()कि वह एक ऐसी इटर्मा वस्तु को लौटाए जिससे प्रत्येक पुनरावृत्त भी iterable हो और इसका उपयोग अधिकांश स्थानों पर किया जा सके जहाँ अन्य पुनरावृत्तियों को स्वीकार किया जाता है। एक उल्लेखनीय अपवाद कोड है जो कई पुनरावृत्तियों को पारित करने का प्रयास करता है। एक कंटेनर वस्तु (जैसे कि list) हर बार जब आप इसे पास करते हैं तो एक नया नया पुनरावृत्ति पैदा करता हैiter()फ़ंक्शन करें या इसे लूप के लिए उपयोग करें। इसे एक पुनरावृत्ति के साथ प्रयास करने से पिछले पुनरावृत्ति पास में उपयोग की जाने वाली समान थकाऊ वस्तु वापस आ जाएगी, जिससे यह खाली कंटेनर की तरह दिखाई देगा।


14

गुइडो इस सवाल का जवाब यहां देते हैं : " एक सूची बनाने के बाद से बस बेकार हो जाएगा "।

वह यह भी कहता है कि सही परिवर्तन एक नियमित forलूप का उपयोग करना है।

map()2 से 3 में परिवर्तित करना शायद list( )इसके आसपास चिपके रहने का एक साधारण मामला नहीं हो सकता है। गुइडो भी कहते हैं:

"यदि इनपुट अनुक्रम समान लंबाई के नहीं हैं, map()तो अनुक्रम की सबसे छोटी अवधि की समाप्ति पर रुक जाएगा। map()पायथन 2.x से पूर्ण संगतता के लिए , अनुक्रमों को भी लपेटें itertools.zip_longest(), जैसे।"

map(func, *sequences)

हो जाता है

list(map(func, itertools.zip_longest(*sequences)))

"


3
map()फंक्शन के साइड इफेक्ट्स के लिए गुइडो कॉमेंट का इस्तेमाल किया जाता है , न कि किसी फनकार के इस्तेमाल पर।
— अबुकाज

4
के साथ परिवर्तन zip_longestगलत है। आपको इसके itertools.starmapसमतुल्य होने के लिए उपयोग करना होगा list(starmap(func, zip_longest(*sequences))):। ऐसा इसलिए है क्योंकि zip_longestट्यूपल्स का उत्पादन होता है, इसलिए कॉल करते समय अलग-अलग तर्कों के बजाय funcएकल-एकल nतर्क प्राप्त होगा । nmap(func, *sequences)
— बकुरीउ

12

पायथन 3 में कई कार्य (न केवल mapबल्कि zip, rangeऔर अन्य) पूरी सूची के बजाय एक पुनरावृत्तिकर्ता को लौटाते हैं। आप एक इटरेटर चाहते हैं (जैसे कि पूरी सूची को मेमोरी में रखने से बचने के लिए) या आप एक सूची (जैसे इंडेक्स करने में सक्षम होना) चाहते हैं।

हालांकि, मुझे लगता है कि पायथन 3 में बदलाव का मुख्य कारण यह है कि जबकि list(some_iterator)रिवर्स समकक्ष का उपयोग करके एक पुनरावृत्ति को सूची में परिवर्तित iter(some_list)करना वांछित परिणाम प्राप्त नहीं करता है क्योंकि पूरी सूची पहले ही निर्मित और स्मृति में रखी गई है।

उदाहरण के लिए, पायथन 3 list(range(n))ठीक काम करता है क्योंकि rangeवस्तु के निर्माण में बहुत कम लागत आती है और फिर इसे सूची में परिवर्तित किया जाता है। हालाँकि, पायथन 2 में iter(range(n))कोई मेमोरी नहीं बचती है क्योंकि पूरी सूची का निर्माण range()इटरेटर के निर्माण से पहले होता है।

इसलिए, अजगर 2 में, अलग कार्यों जैसे पुनरावर्तक के बजाय एक सूची बनाने के लिए आवश्यक हैं imapके लिए map(हालांकि वे कर रहे हैं काफी बराबर नहीं ), xrangeके लिए range, izipके लिए zip। इसके विपरीत पाइथन 3 के लिए केवल एक फ़ंक्शन की आवश्यकता होती है क्योंकि list()कॉल आवश्यकता होने पर पूरी सूची बनाता है।


पायथन में AFAIK 2.7 itertoolsपुनरावृत्तियों से भी कार्य करता है। इसके अलावा, मैं पुनरावृत्तियों को आलसी सूचियों के रूप में नहीं देखूंगा, क्योंकि सूचियों को कई बार पुनरावृत्त किया जा सकता है और यादृच्छिक रूप से एक्सेस किया जा सकता है।
— अबुकज

@abukaj ठीक है, धन्यवाद, मैंने अपने उत्तर को स्पष्ट करने की कोशिश की है
— क्रिस_न्ड्स

@IgorRivin तुम्हारा क्या मतलब है? अजगर 3 mapवस्तुओं में एक next()विधि होती है। पायथन 3 rangeरेंज ऑब्जेक्ट्स कड़ाई से
— चलने वाले

@ Anhonda वितरण python 3.6.2 में @Chris_Rands, foo = map(lambda x: x, [1, 2, 3])एक मैप ऑब्जेक्ट करता है foo। कर foo.next()एक त्रुटि के साथ वापस आता है:'map' object has no attribute 'next'
— इगोर रिविन

1
@IgorRivin: शुरुआत और समाप्ति के तरीके __पायथन के लिए आरक्षित हैं; उस आरक्षण के बिना, आपके पास चीजों को भेद करने में समस्या है, जिसके nextलिए सिर्फ एक तरीका है (वे वास्तव में पुनरावृत्त नहीं हैं) और वे चीजें जो पुनरावृत्तियां हैं। व्यवहार में, आपको विधियों को छोड़ देना चाहिए और केवल next()फ़ंक्शन (जैसे next(foo)) का उपयोग करना चाहिए , जो कि 2.6 से प्रत्येक पायथन संस्करण पर ठीक से काम करता है। यह उसी तरह से है जिसका आप उपयोग करते हैं len(foo)भले ही foo.__len__()ठीक काम करेगा; डंडर विधियों को आम तौर पर सीधे नहीं कहा जाता है, लेकिन इसका मतलब है कि कुछ अन्य ऑपरेशन के हिस्से के रूप में।
— शैडो रेंजर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.