जब समारोह बयान क्रियान्वित कर रहे हैं वे अपने (lexically) संलग्न गुंजाइश के लिए बाध्य कर रहे हैं।
अपने स्निपेट में, लैम्बडा वैश्विक दायरे से बंधे हैं, क्योंकि for
सूट को पायथन में स्वतंत्र रूप से स्कॉप्ड इकाई के रूप में निष्पादित नहीं किया जाता है। for
लूप के अंत में, num
संलग्न क्षेत्र में बाध्य है। डेमो:
for num in range(1, 6):
pass
assert num == 5 # num is now bound in the enclosing scope
तो जब आप for
पाश में पहचानकर्ता बाँध आप वास्तव में संलग्न गुंजाइश जोड़ तोड़ कर रहे हैं।
for num in range(1, 6):
spam = 12
assert num == 5 # num is now bound in the enclosing scope
assert spam == 12 # spam is also bound in the enclosing scope
सूची comprehensions के लिए एक ही सौदा:
[num for num in range(1, 6)]
assert num == 5
मन उड़ाने, मुझे पता है। कोई भी, हमारे नए ज्ञान के साथ, हम यह निर्धारित कर सकते हैं कि आपके द्वारा बनाए जा रहे लैम्बडास (एकल) num
पहचानकर्ता को संलग्न क्षेत्र में बाध्य हैं। यही कारण है कि इस अधिक समझ बनाने बनाना चाहिए:
functions = []
for number in range(1, 6):
def fun():
return number
functions.append(fun)
assert all(fun() == 5 for fun in functions)
assert all(fun() is number for fun in functions)
और यहाँ सबसे अच्छे हिस्से को दर्शाता है कि यह और भी है:
# Same as above -- commented out for emphasis.
#functions = []
#for number in range(1, 6):
# def fun():
# return number
# functions.append(fun)
#assert all(fun() == 5 for fun in functions)
#assert all(fun() is number for fun in functions)
number = 6 # Rebind 6 in the scope and see how it affects the results.
assert all(fun() == 6 for fun in functions)
तो इस का हल, ज़ाहिर है, के लिए एक नया संलग्न गुंजाइश बनाना है प्रत्येक number
आप बांधना चाहते हैं। पायथन में, आप मॉड्यूल, कक्षाओं और कार्यों के साथ नए संलग्नक स्कोप बना सकते हैं। किसी अन्य फ़ंक्शन के लिए नए संलग्न क्षेत्र को बनाने के लिए फ़ंक्शन का उपयोग करना आम बात है।
अजगर में, एक बंद एक समारोह है कि एक और समारोह देता है। एक समारोह कन्स्ट्रक्टर की तरह। निम्न उदाहरण में get_fun
की जाँच करें:
def get_fun(value):
""":return: A function that returns :param:`value`."""
def fun(): # Bound to get_fun's scope
return value
return fun
functions = []
for number in range(1, 6):
functions.append(get_fun(number))
assert [fun() for fun in functions] == range(1, 6)
get_fun
के बाद से एक समारोह है, यह अपने स्वयं के आंतरिक गुंजाइश है करने के लिए हो जाता है। प्रत्येक बार जब आप get_fun
को किसी मान के साथ कॉल करते हैं, तो इसके अंदर बाइंडिंग का ट्रैक रखने के लिए एक छोटी सी तालिका बनाई जाती है; यानी यह कहता है, "इस दायरे में, value
पहचानकर्ता पास की गई चीज़ को इंगित करता है।" उस दायरे को फ़ंक्शन निष्पादन के अंत में दूर चला जाता है, जब तक कि इसके आसपास लटकने का कोई कारण न हो।
यदि आप किसी दायरे से किसी फ़ंक्शन को वापस कर रहे हैं, तो यह "स्कोप टेबल" के हिस्सों के आसपास घूमने का एक अच्छा कारण है - जो फ़ंक्शन आप लौट रहे हैं वह उस स्कोप टेबल से चीजों को संदर्भित कर सकता है जब आप इसे कॉल करते हैं बाद में। इसी कारण से, fun
get_fun
के भीतर बनाया गया है पाइथन fun
get_fun
की स्कोप तालिका बताता है, जो fun
इसकी आवश्यकता होने पर आसान रहता है।
आप Python docs on the execution model में विवरण और तकनीकी शब्दावली (जिसे मैंने थोड़ा नरम किया) के बारे में अधिक पढ़ सकते हैं। आप संलग्न क्षेत्र के हिस्सों को भी देख सकते हैं कि एक समारोह print fun.__closure__
के साथ संदर्भित करता है। [] के बजाय) का उपयोग करने के
# Same as before, commented out for emphasis.
#functions = []
#for number in range(1, 6):
# functions.append(get_fun(number))
#assert [fun() for fun in functions] == range(1, 6)
print functions[0].__closure__
# Produces: (<cell at 0x8dc30: int object at 0x1004188>,)
कूल। क्या यह "हैक" कहीं भी दस्तावेज है? क्या करी करने के लिए कोई बेहतर तरीका है? इसके अलावा, कृपया अपने घूर्णन बिस्तर को फिर से कभी भी न दें। –
मैंने कभी भी इसे किसी दस्तावेज़ में स्पष्ट रूप से उल्लेख नहीं किया है। यह इस तथ्य का लाभ उठा रहा है कि फ़ंक्शन पैरामीटर के लिए डिफ़ॉल्ट मान फ़ंक्शन के निर्माण के समय असाइन किए गए हैं, जो दस्तावेज है। – recursive
यह उदाहरण लगभग समान है [विभिन्न मूल्यों के साथ लूप में परिभाषित लैम्बडास एक ही परिणाम लौटाते हैं?] (Https://docs.python.org/3.4/faq/programming.html#why-do-lambdas- दस्तावेज़ों में परिभाषित-में-एक-लूप-साथ-अलग-मूल्य-सभी-वापसी-एक-परिणाम)। – abarnert