2012-05-20 7 views
19

मैं पाइथन सीखने के बिंदु पर हूं जहां मैं the Mutable Default Argument problem से निपट रहा हूं।कोई भी पाइथन के म्यूटेबल डिफ़ॉल्ट तर्क समस्या को ठीक करने का उपयोग क्यों नहीं करता है?

def bad_append(new_item, a_list=[]): 
    a_list.append(new_item) 
    return a_list 

def good_append(new_item, a_list=None): 
    if a_list is None: 
     a_list = [] 
    a_list.append(new_item) 
    return a_list 

मैं समझता हूँ कि a_list केवल आरंभ नहीं हो जाता जब def बयान पहले का सामना करना पड़ा है, और यही कारण है कि bad_append की आगामी कॉल एक ही सूची ऑब्जेक्ट का उपयोग है।

मैं क्या समझ में नहीं आता क्यों good_append किसी भी अलग अलग काम करता है। ऐसा लगता है कि a_listअभी भी केवल एक बार आरंभ किया जाएगा; इसलिए, if बयान केवल समारोह के पहले मंगलाचरण पर सही हो सकता है, जिसका अर्थ है a_list केवल पहले मंगलाचरण पर [] पर रीसेट जायेगा, जिसका अर्थ है कि यह अभी भी सभी पिछले new_item मूल्यों जमा होता है और अभी भी गाड़ी हो।

ऐसा क्यों नहीं है? मुझे क्या अवधारणा याद आ रही है? a_list कैसे हर बार good_append रनों को साफ कर देता है?

उत्तर

11

डिफ़ॉल्ट (या किसी अन्य डिफ़ॉल्ट मान उस बात के लिए,) a_list का मूल्य समारोह के अंदरूनी हिस्सों में संग्रहीत किया जाता है एक बार यह शुरू कर दिया गया है और इस तरह किसी भी तरह से संशोधित किया जा सकता:

>>> def f(x=[]): return x 
... 
>>> f.func_defaults 
([],) 
>>> f.func_defaults[0] is f() 

तो मूल्य func_defaults में, एक ही जो साथ ही बाहर से यह तक पहुँचने के लिए समारोह (अंदर जाना जाता है और मेरे उदाहरण में लौट रहा है।

IOW, क्या होता है जब बुला f() एक अंतर्निहित x = f.func_defaults[0] है। उस वस्तु बाद में संशोधित किया गया है, तो आप उस संशोधन को बनाए रखेंगे।

इसके विपरीत, के अंदर एक असाइनमेंट हमेशा एक नया [] मिलता है। कोई भी संशोधन तब तक चलेगा जब तक कि [] का अंतिम संदर्भ नहीं चला है; अगले फ़ंक्शन कॉल पर, एक नया [] बनाया गया है।

IOW फिर, यह है कि [] हर निष्पादन पर एक ही वस्तु हो जाता है सच नहीं है, लेकिन यह (डिफ़ॉल्ट तर्क के मामले में) है केवल एक बार मार डाला और फिर संरक्षित।

+1

बहुत बहुत धन्यवाद; वाक्य "एफ() 'को कॉल करते समय क्या होता है एक अंतर्निहित' x = f.func_defaults [0] '" मेरी समझ के लिए महत्वपूर्ण था। –

+1

... इतना है कि मैं अपना दिमाग बदल रहा हूं, फिर से, और इसे सही उत्तर के रूप में चिह्नित कर रहा हूं। –

14

समस्या केवल तभी मौजूद है जब डिफ़ॉल्ट मान उत्परिवर्तनीय है, जो None नहीं है। फ़ंक्शन ऑब्जेक्ट के साथ संग्रहीत किया जाता है डिफ़ॉल्ट मान है। जब फ़ंक्शन कहा जाता है, तो फ़ंक्शन का संदर्भ डिफ़ॉल्ट मान के साथ प्रारंभ किया जाता है।

a_list = [] 

सिर्फ वर्तमान समारोह कॉल के संदर्भ में नाम a_list करने के लिए एक नई वस्तु प्रदान करती है। यह किसी भी तरह से None संशोधित नहीं करता है।

+0

मेरी धारणा यह है कि ओपी का असाइनमेंट और गुंजाइश का मानसिक मॉडल गलत था। मैं उस स्पष्ट को बनाने के लिए उत्तर दोबारा लिखता हूं। – phihag

+0

असाइनमेंट का मेरा मानसिक मॉडल वास्तव में गलत था; वास्तव में अब भी कि मैं समस्या को कुछ हद तक बेहतर समझता हूं, यह अभी भी हो सकता है। जो मुझे समझ में नहीं आया था कि जब आप फ़ंक्शन परिभाषा में 'a_list = none' करते हैं, तो फ़ंक्शन में आंतरिक रूप से * एक ही ऑब्जेक्ट के लिए एक और नाम होता है *, और पैरामीटर का दृश्य नाम उस ऑब्जेक्ट को उस ऑब्जेक्ट पर फिर से सौंप दिया जाता है समारोह के हर आमंत्रण। –

4

नहीं है, good_insert में a_list केवल एक बार initalised नहीं है।

प्रत्येक बार फ़ंक्शन को a_list तर्क निर्दिष्ट किए बिना बुलाया जाता है, डिफ़ॉल्ट का उपयोग किया जाता है और list का एक नया उदाहरण उपयोग और लौटाया जाता है, नई सूची डिफ़ॉल्ट मान को प्रतिस्थापित नहीं करती है।

20

ऐसा लगता है कि a_list की तरह अभी भी प्रारंभ किया जाएगा केवल एक बार

"प्रारंभ" कुछ है कि अजगर में चर के लिए होता है, क्योंकि अजगर में चर सिर्फ नाम हैं नहीं है। "प्रारंभिकरण" केवल वस्तुओं के साथ होता है, और यह वर्ग '__init__ विधि के माध्यम से किया जाता है।

जब आप a = 0 लिखते हैं, तो यह एक असाइनमेंट है। यह कह रहा है कि "a अभिव्यक्ति 0 अभिव्यक्ति द्वारा वर्णित ऑब्जेक्ट को संदर्भित करेगा"। यह प्रारंभिक नहीं है; a किसी भी समय किसी भी प्रकार के किसी भी अन्य नाम का नाम दे सकता है, और यह a पर कुछ और निर्दिष्ट करने के परिणामस्वरूप होता है। असाइनमेंट सिर्फ असाइनमेंट है। पहला एक विशेष नहीं है।

जब आप def good_append(new_item, a_list=None) लिखते हैं, तो यह a_list "प्रारंभिक" नहीं है। यह किसी ऑब्जेक्ट का आंतरिक संदर्भ स्थापित कर रहा है, None का मूल्यांकन करने का नतीजा, ताकि जब good_append को दूसरे पैरामीटर के बिना बुलाया जाता है, तो वह ऑब्जेक्ट स्वचालित रूप से a_list पर असाइन किया जाता है।

अर्थ a_list केवल पहले मंगलाचरण

नहीं है, a_list[] के लिए किसी भी समय है कि a_listNone के साथ शुरू करने के लिए है सेट हो जाता है पर [] पर रीसेट हो जाएगा। यही है, जब None स्पष्ट रूप से पारित किया जाता है, या तर्क छोड़ दिया जाता है।

[] के साथ समस्या होती है क्योंकि अभिव्यक्ति[] केवल इस संदर्भ में एक बार का मूल्यांकन किया है। जब फ़ंक्शन संकलित किया जाता है, [] का मूल्यांकन किया जाता है, विशिष्ट सूची ऑब्जेक्ट बनाया जाता है - जो प्रारंभ करने के लिए खाली होता है - और उस ऑब्जेक्ट को डिफ़ॉल्ट के रूप में उपयोग किया जाता है।

कैसे a_list हर बार good_append रन साफ ​​होता है?

ऐसा नहीं है। यह होने की जरूरत नहीं है।

आप जानते हैं कि समस्या को "mutable डिफ़ॉल्ट तर्क" के रूप में वर्णित किया गया है?

None उत्परिवर्तनीय नहीं है।

समस्या तब होती है जब आप ऑब्जेक्ट संशोधित करते हैं कि पैरामीटर डिफ़ॉल्ट के रूप में है।

a_list = [] जो भी ऑब्जेक्ट a_list पहले निर्दिष्ट किया गया है उसे संशोधित नहीं करता है। यह नहीं कर सकते; मनमाने ढंग से वस्तुओं को जादुई रूप से रिक्त सूचियों में स्थानांतरित नहीं किया जा सकता है। a_list = [] का अर्थ है "a_list जो पहले उल्लेख किया गया था उसका जिक्र करना बंद कर देगा, और [] का जिक्र करना शुरू करें"। पहले से संदर्भित ऑब्जेक्ट अपरिवर्तित है।

जब समारोह संकलित किया गया है, और तर्क में से एक एक डिफ़ॉल्ट मान, कि मूल्य नहीं है - एक वस्तु - समारोह में शामिल किया हुआ हो जाता है (जो भी है, जो अपने आप, एक वस्तु!)। जब आप किसी ऑब्जेक्ट को म्यूट करते हुए कोड लिखते हैं, तो ऑब्जेक्ट म्यूट करता है। यदि ऑब्जेक्ट को संदर्भित किया जाता है तो यह कार्य फ़ंक्शन में बेक्ड ऑब्जेक्ट होता है, यह अभी भी म्यूट करता है।

लेकिन आप None को म्यूट नहीं कर सकते हैं। यह अपरिवर्तनीय है।

आप [] को बदल सकते हैं। यह एक सूची है, और सूचियां उत्परिवर्तनीय हैं। सूची में किसी आइटम को जोड़ना सूची को बदल देता है।

+0

महान उत्तर के लिए धन्यवाद। मैं खुद को यह तय करने की कोशिश कर रहा हूं कि इस उत्तर को चिह्नित करना है या @ glglgl को सही के रूप में चिह्नित करना है या नहीं। दूसरे जवाब में एक रोशनी वाक्यांश है जो मुझे आपके उत्तर को समझने में सक्षम बनाता है; पूरी तरह से आपका जवाब अधिक गहन और समझदार है, लेकिन किसी भी तरह से प्रकाश उसी तरह से क्लिक नहीं करता है। यदि किसी प्रश्न पर दो हरे रंग के चेकमार्क देने का कोई तरीका था, तो आपका बिल्कुल दूसरा होगा (और अगर मैं वफ़ल रखता हूं तो फिर से एकमात्र हो सकता है)। –

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

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