चलिए सवाल को आसान करते हैं। निर्धारित करें:
def get_petters():
for animal in ['cow', 'dog', 'cat']:
def pet_function():
return "Mary pets the " + animal + "."
yield (animal, pet_function)
फिर, जैसे प्रश्न में, हम प्राप्त करते हैं:
>>> for name, f in list(get_petters()):
... print(name + ":", f())
cow: Mary pets the cat.
dog: Mary pets the cat.
cat: Mary pets the cat.
लेकिन अगर हम list()
पहले बनाने से बचते हैं :
>>> for name, f in get_petters():
... print(name + ":", f())
cow: Mary pets the cow.
dog: Mary pets the dog.
cat: Mary pets the cat.
क्या चल रहा है? यह सूक्ष्म अंतर हमारे परिणामों को पूरी तरह से क्यों बदलता है?
यदि हम देखते हैं list(get_petters())
, तो यह बदलते स्मृति पतों से स्पष्ट है कि हम वास्तव में तीन अलग-अलग कार्य करते हैं:
>>> list(get_petters())
[('cow', <function get_petters.<locals>.pet_function at 0x7ff2b988d790>),
('dog', <function get_petters.<locals>.pet_function at 0x7ff2c18f51f0>),
('cat', <function get_petters.<locals>.pet_function at 0x7ff2c14a9f70>)]
हालाँकि, cell
इन कार्यों के लिए बाध्य हैं:
>>> for _, f in list(get_petters()):
... print(f(), f.__closure__)
Mary pets the cat. (<cell at 0x7ff2c112a9d0: str object at 0x7ff2c3f437f0>,)
Mary pets the cat. (<cell at 0x7ff2c112a9d0: str object at 0x7ff2c3f437f0>,)
Mary pets the cat. (<cell at 0x7ff2c112a9d0: str object at 0x7ff2c3f437f0>,)
>>> for _, f in get_petters():
... print(f(), f.__closure__)
Mary pets the cow. (<cell at 0x7ff2b86b5d00: str object at 0x7ff2c1a95670>,)
Mary pets the dog. (<cell at 0x7ff2b86b5d00: str object at 0x7ff2c1a952f0>,)
Mary pets the cat. (<cell at 0x7ff2b86b5d00: str object at 0x7ff2c3f437f0>,)
दोनों छोरों के लिए, cell
ऑब्जेक्ट पूरे पुनरावृत्तियों में समान रहता है। हालाँकि, उम्मीद के मुताबिक, यह विशिष्ट str
संदर्भ दूसरे लूप में भिन्न होता है। cell
वस्तु को संदर्भित करता है animal
, जो जब बनाई गई है get_petters()
कहा जाता है। हालांकि, यह animal
बदलता है कि जनरेटर फ़ंक्शन के रूप मेंstr
यह किस ऑब्जेक्ट को संदर्भित करता है ।
पहले लूप में, प्रत्येक पुनरावृत्ति के दौरान, हम सभी को बनाते हैं f
, लेकिन जनरेटर get_petters()
के पूरी तरह से समाप्त होने के बाद ही हम उन्हें कॉल करते हैं और list
पहले से ही एक फ़ंक्शन बनाया जाता है।
दूसरे लूप में, प्रत्येक पुनरावृत्ति के दौरान, हम get_petters()
जनरेटर को रोक रहे हैं और f
प्रत्येक ठहराव के बाद बुला रहे हैं । इस प्रकार, हम animal
उस समय का मान पुनः प्राप्त करते हैं, जब जनरेटर फ़ंक्शन रोका जाता है।
@Claudiu एक ऐसे ही सवाल के जवाब में कहते हैं :
तीन अलग-अलग फ़ंक्शंस बनाए जाते हैं, लेकिन उनमें से प्रत्येक को उस वातावरण में बंद किया जाता है जिसे वे परिभाषित करते हैं - इस मामले में, वैश्विक वातावरण (या बाहरी फ़ंक्शन का वातावरण यदि लूप को किसी अन्य फ़ंक्शन के अंदर रखा जाता है)। यह वास्तव में समस्या है, हालांकि - इस वातावरण में, animal
उत्परिवर्तित है, और क्लोजर सभी समान हैं animal
।
[संपादक नोट: i
बदल दिया गया है animal
।]
for animal in ['cat', 'dog', 'cow']
... मुझे यकीन है कि किसी के साथ आ जाएगा हूँ और यद्यपि यह समझाने - यह उन अजगर पकड़ लिया है :) में से एक है