2009-12-17 16 views
7

कोड के इस स्निपेट को देखते हुए देखते हुए:अजगर lambdas और

funcs = [] 
for x in range(3): 
    funcs.append(lambda: x) 
print [f() for f in funcs] 

मैं इसे [0, 1, 2] मुद्रित करने के लिए उम्मीद करेंगे, लेकिन इसके बजाय यह [2, 2, 2] प्रिंट करता है। क्या कोई मौलिक है कि मैं लापता कैसे काम करता हूं इस बारे में याद कर रहा हूं?

+2

आम सवाल पूछा, (और जवाब) कम से कम एक बार पहले: http://stackoverflow.com/questions/233673/लेक्सिकल-क्लोजर-इन-पायथन –

+0

@Vladimir: हाँ, लेकिन दोनों का शीर्षक काफी अलग है, मुझे कभी नहीं लगता कि वे एक ही चीज़ के बारे में हैं। – OscarRyz

उत्तर

8

यह अजगर में अक्सर सवाल है। मूल रूप से स्कोपिंग ऐसा होता है कि जब f() कहा जाता है, तो यह x के वर्तमान मान का उपयोग करेगा, लैम्बडा के गठन के समय x का मान नहीं। वहाँ एक मानक समाधान नहीं है:

funcs = [] 
for x in range(10): 
funcs.append(lambda x=x: x) 
print [f() for f in funcs] 

lambda x = x retrieves के उपयोग और x के वर्तमान मूल्य बचाता है।

5

x मॉड्यूल-स्तर x (जो लूप के लिए छोड़ दिया गया है) से बंधे हैं।

एक छोटी सी साफ:

funcs = [] 

for x in range(10): 
    funcs.append(lambda: x) 

x = 'Foo' 

print [f() for f in funcs] 

# Prints ['Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo'] 
4

आप उत्तर जानते हैं: हाँ। ;) आराम करें, हालांकि, यह उभरते पायथनिस्टों के लिए एक बहुत ही आम खोज है। जब आप फ़ंक्शन या लैम्ब्डा को परिभाषित करते हैं, तो संदर्भ फ़ंक्शन उस फ़ंक्शन के अंदर "बनाए गए" नहीं होते हैं, यह चर पर एक बंद बनाता है। प्रभाव यह है कि फ़ंक्शन को कॉल करते समय आपको वैरिएबल का मान मिलता है, परिभाषा समय पर मान नहीं। (आप बाद वाले की उम्मीद कर रहे थे।)

इससे निपटने के कुछ तरीके हैं। प्रथम अतिरिक्त चर बाध्यकारी है:

funcs = [] 
for x in range(10): 
    funcs.append(lambda x=x: x) 
print [f() for f in funcs] 
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

दूसरा तरीका थोड़ा और अधिक औपचारिक है:

from functools import partial 
funcs = [] 
for x in range(10): 
    funcs.append(partial(lambda x: x, x)) 
print [f() for f in funcs] 
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
संबंधित मुद्दे