2011-03-09 3 views
5
>>> list1 = [] 
>>> list2 = list1 
>>> list2 += [1] 
>>> print list1 
[1] 

पायथन में जगहों पर संवर्धित असाइनमेंट (+ =) सूचियों के लिए प्रेरणा क्या थी? आपरेशन मूल सूची को संशोधित करता है -

>>> list1 = [] 
>>> list2 = list1 
>>> list2 = list2 + [1] 
>>> print list1 
[] 

को यह तुलना वहाँ एक कारण है कि '+ =' है?

संपादित करें: बस मेरे सवाल का बनाने के लिए एक सा साफ

भाषाओं कि मैं जानता हूँ कि अधिकांश '+ =' - ऑपरेटर इस तरह से काम नहीं करता है और मुझे पता है क्यों यह था चाहते हैं पायथन में इस तरह से डिजाइन किया गया।

कुछ उदाहरण:

रूबी

irb(main):001:0> l = [] 
irb(main):002:0> a = l 
irb(main):003:0> a += [2] 
irb(main):004:0> l 
=> [] 

स्काला आदि ..

+0

दिलचस्प का उपयोग करके सूची तत्व-दर-तत्व (list2 = [i for in list1]) या कॉपी कर सकते हैं। शायद क्योंकि 'list2 = list2 + [1] 'में,' list2 + [1] 'एक नई सूची बनाता है, जिसे तब' list2' को असाइन किया जाता है। मुझे लगता है कि यह उन "quirks" में से एक है जो pythonista के लिए उपयोग किया जाता है। हालांकि यह एक शुरुआत के लिए भ्रमित है। – Zabba

+0

@MartijnPieters: मुझे लगता है कि सवाल थोड़ा अलग है .. मैं यहां डिजाइन के कारण से पूछ रहा हूं (क्योंकि यह उसी ऑपरेटर के उदाहरण के मुकाबले आईएमएचओ थोड़ा अजीब है उदाहरण के लिए स्कैला और रूबी में) और दूसरा सवाल क्या हो रहा है "क्या हो रहा है?"। – mkorpela

+0

प्रेरणा के लिए [मूल पीईपी (पायथन संवर्द्धन प्रस्ताव] (http://www.python.org/dev/peps/pep-0203/) देखें। * इस सुविधा को पायथन में जोड़ने के दो मुख्य कारण हैं: सादगी अभिव्यक्ति, और इन-प्लेस ऑपरेशंस के लिए समर्थन। अंतिम परिणाम वाक्यविन्यास की सादगी और अभिव्यक्ति की सादगी के बीच एक व्यापार है; अधिकांश नई सुविधाओं की तरह, संवर्धित असाइनमेंट पहले से असंभव कुछ भी नहीं जोड़ता है। यह केवल इन चीजों को आसान बनाता है । * –

उत्तर

7

पायथन 2.6.4 दस्तावेज से, खंड 6.2.1। (संवर्धित काम बयानों)

x += 1 की तरह एक संवर्धित काम अभिव्यक्ति x = x + 1 के रूप में लिखा जा सकता है एक ऐसी ही प्राप्त करने के लिए, लेकिन वास्तव में नहीं के बराबर प्रभाव। संवर्धित संस्करण में, एक्स का मूल्यांकन केवल एक बार किया जाता है। साथ ही, जब भी संभव हो, वास्तविक ऑपरेशन में किया जाता है, जिसका अर्थ है कि एक नई वस्तु बनाने और लक्ष्य को असाइन करने के बजाय, पुरानी वस्तु को इसके बजाय संशोधित किया गया है।

[जोर जोड़ा]

+2

पृष्ठभूमि में क्या हो रहा है इसके बारे में थोड़ा अतिरिक्त स्पष्टीकरण: असल में, ये दो असाइनमेंट एक ही ऑब्जेक्ट की विधि का उपयोग नहीं करते हैं, यही कारण है कि व्यवहार अलग है। 'X = x + 1'' __add __() 'विधि का उपयोग करता है, जो एक नई वस्तु देता है, जबकि' x + = 1' '__iadd __() 'विधि का उपयोग करता है, जो वस्तु को जगह में संशोधित करता है। – MatToufoutu

0

है कि कैसे += काम करने के लिए माना जाता है। सामान्य तौर पर,

a += b 

मतलब है

a = a + b 

लेकिन अपने विशेष परिदृश्य एक अलग समस्या है। जब आप

list2 = list1 

कोई प्रतिलिपि नहीं बनाई जाती है; list2 अब एक ही सूची का संदर्भ है। list2 पर कोई भी संशोधन list1 और इसके विपरीत में दिखाई देगा।

अपने दूसरे कोड स्निपेट में, list2 + [1] एक नई सूची जो बाद में list2 को सौंपा गया है निर्माण करती है। चूंकि यह प्रति list1 से स्वतंत्र है, इसलिए list1 में कोई परिवर्तन दिखाई नहीं दे रहा है।

(Nitpicker के कोने: का उपयोग ऑपरेटर ओवरलोडिंग, यह एक वर्ग है कि += के लिए अलग तरह से व्यवहार करता है निर्माण संभव है क्या नहीं बस ... नहीं है।।।)

+0

तो यह इस तरह से क्यों काम नहीं करता है? – mkorpela

+0

लेकिन ओपी कह रहा है कि आपके उत्तर में जो व्यवहार आप उल्लेख करते हैं, वह * नहीं * होता है! – Zabba

+0

क्षमा करें, मैं अपने जवाब में बहुत जल्दबाजी में था। संपादित। – Thomas

2

ठीक है, क्योंकि है कि कैसे यह है काम करता है। जब आप list2 = list2 + [1] लिखते हैं, तो आप नई सूची बनाते हैं और इसे list2 नाम से बांधते हैं। जब आप += का उपयोग करते हैं, तो ऑपरेशन "जगह में" होता है। तो जब list1 और list2 एक ही ऑब्जेक्ट का संदर्भ देता है, जो यहां है, तो आप इसे += ऑपरेटर के साथ संशोधित करते हैं।

4

जब आप list2 += [1] करते हैं तो आप सूची में सूची को संशोधित कर रहे हैं। और यही कारण है कि आप सूची बिंदुओं को संदर्भ में नहीं बदलते हैं, लेकिन आप सूची को सीधे बदल रहे हैं। जब आप list2 = list2 + [1] करते हैं, तो आप एक नई सूची बना रहे हैं।

>>> l = [] 
>>> id(l) 
41523720L 
>>> l += [3] 
>>> id(l) 
41523720L  # same as l = [] 
>>> l = l+[3] 
>>> id(l) 
41532232L 

यह अंतर बताता है।

10

संदर्भ द्वारा संग्रहीत पायथन में सूचीबद्ध है।

इसका मतलब यह है कि जब आप list2 = list1 करते हैं, आप सूची की एक प्रति नहीं कर रहे हैं - आप केवल कह रहे हैं "list2 एक ही बात list1 करता है को संदर्भित करता है," अर्थात्, सूची आप मूल रूप से बनाया है जब आप list1 = [] किया था।

अजगर को निर्दिष्ट += मतलब करने के लिए सूचियों के लिए "जगह में संलग्न", क्योंकि समय है जब आप सूची में += उपयोग कर रहे हैं के अधिकांश, कि क्या आप क्या करना चाहते है - आप आमतौर पर हर एक नई सूची बनाने के लिए नहीं करना चाहते हैं समय आप एक तत्व जोड़ते हैं।

इस प्रकार, जब आप list2 को संलग्न ", एक ही वस्तु list1 करता है को संदर्भित करता है" जो है, और फिर list1 से पढ़ा, तो आप संलग्न आइटम देखते हैं, के रूप में की उम्मीद है के बाद से उन दोनों को एक ही सूची में इशारा करते हैं।

+ के साथ, तथापि, एक नई सूची हमेशा बनाई गई है, क्योंकि यह मतलब नहीं है जगह में ऑपरेंड के या तो संशोधित करने के लिए (के बाद से a+ba या b के संशोधन संकेत नहीं करता है)।

इसलिए, जब आप list2 = list2 + [1] करते हैं, आप एक नई सूची है कि मूल ऑब्जेक्ट की सामग्री के सभी list2 और भी 1 द्वारा की ओर इशारा किया बनाते हैं और फिर कहते हैं कि list2 अब संदर्भ नई सूची। चूंकि यह अब list1 की तुलना में एक अलग सूची का संदर्भ देता है, जब आप list1 से पढ़ने के लिए जाते हैं, तो भी आप अतिरिक्त 1 के बिना मूल सूची देखते हैं।

+1

+1: मुझे लगता है कि यह ओपी भ्रम का वास्तविक स्रोत है। –

5

documentation regarding Emulating numeric types में देखें, जो तरीकों है कि इस व्यवहार को लागू वर्णन करता है। यह सूचियों पर भी लागू होता है:

इन विधियों को संवर्धित अंकगणितीय असाइनमेंट (+=, -=, *=, /=, //=, %=, **=, <<=, >>=, &=, ^=, |=) को लागू करने के लिए कहा जाता है। इन तरीकों को ऑपरेशन को (self संशोधित करने) का प्रयास करने का प्रयास करना चाहिए और परिणाम (जो हो सकता है, लेकिन self) नहीं होना चाहिए। यदि कोई विशिष्ट विधि परिभाषित नहीं की जाती है, तो संवर्धित असाइनमेंट सामान्य तरीकों पर वापस आ जाता है। उदाहरण के लिए, x += y कथन निष्पादित करने के लिए, जहां x एक कक्षा का एक उदाहरण है जिसमें __iadd__() विधि है, x.__iadd__(y) कहा जाता है। यदि x एक कक्षा का एक उदाहरण है जो __iadd__() विधि, x.__add__(y) और y.__radd__(x) को परिभाषित नहीं करता है, तो x + y के मूल्यांकन के साथ माना जाता है।

0

पायथन में, आप वैरिएबल नामों के बारे में क्या सोचते हैं, ज्यादातर मामलों में पॉइंटर्स के समान होते हैं; "=" किसी ऑब्जेक्ट की प्रतिलिपि नहीं करता है, यह उस ऑब्जेक्ट में एक नया नाम बांधता है (अन्य संदर्भों में "संदर्भ द्वारा प्रतिलिपि")।तो list2 = list1 का अर्थ है कि दोनों नाम समान सूची को इंगित करते हैं, न कि एक समान सूची की केवल दो प्रतियां। इसलिए, "+ =" एकल सूची को संशोधित करता है जो दोनों नामों द्वारा इंगित किया जाता है।

आप copy मॉड्यूल (list2 = copy.copy(list1))

संबंधित मुद्दे