2012-12-25 23 views
5

Possible Duplicate:
Python lambdas and scopingअजगर में कार्यों की सूची निर्धारित

मैं आशा करता हूं 3 निरंतर मूल्यों 0, 1 और 2 लेने कार्यों की एक सूची तैयार हैं निम्नलिखित:

lis = [] 
for i in range(3): 
    lis.append(lambda: i) 

लेकिन वे सभी अंत मूल्य लेने 2. मैं समस्या को ठीक करने के लिए गहरी आवाज की उम्मीद करता हूं लेकिन यह काम नहीं कर रहा है।

+3

यह एक मानक प्रश्न है। जैसे http://stackoverflow.com/questions/1107210/python-lambda-problems, http://stackoverflow.com/questions/1924214/python-lambdas-and-scoping। कई, * कई * अधिक। –

+0

संबंधित: [? क्यों मानचित्र के परिणाम() और सूची समझ अलग हैं] (http://stackoverflow.com/questions/139819/why-results-of-map-and-list-comprehension-are-different) – jfs

उत्तर

1

आप पाश कुछ इस तरह लेखन से बचने के लिए:

lis.append(lambda: 0) 
lis.append(lambda: 1) 
lis.append(lambda: 2) 

आपका इरादा लैम्ब्डा कार्यों कि निरंतर पूर्णांकों लौट लिखने के लिए है। लेकिन आप को परिभाषित करने और उस वस्तु i लौटा रहा है एक समारोह जोड़कर कर रहे हैं। इस प्रकार 3 संलग्न कार्य समान हैं।

कार्यों के पीछे बाइट कोड बनाया रिटर्न i:

In [22]: import dis 
In [25]: dis.dis(lis[0]) 
    3   0 LOAD_GLOBAL    0 (i) 
       3 RETURN_VALUE   

In [26]: dis.dis(lis[1]) 
    3   0 LOAD_GLOBAL    0 (i) 
       3 RETURN_VALUE   

In [27]: dis.dis(lis[2]) 
    3   0 LOAD_GLOBAL    0 (i) 
       3 RETURN_VALUE 

कॉलिंग उन कार्यों में से किसी i के नवीनतम मान अपने नमूना कोड में 2 रिटर्न:

In [28]: lis[0]() 
Out[28]: 2 

यदि आप हटाना

In [29]: del i 

In [30]: lis[0]() 
--------------------------------------------------------------------------- 
NameError         Traceback (most recent call last) 
<ipython-input-30-c9e334d64652> in <module>() 
----> 1 lis[0]() 

<ipython-input-18-15df6d11323a> in <lambda>() 
     1 lis = [] 
     2 for i in range(3): 
----> 3  lis.append(lambda: i) 

NameError: global name 'i' is not defined 
: i वस्तु, आपको कोई त्रुटि मिलती

In [31]: lis = [] 
    ...: for i in range(3): 
    ...:  exec 'lis.append(lambda: {})'.format(i) 
    ...: 
निम्न परिणाम के साथ

:


एक समाधान स्थिरांक आप की जरूरत के साथ कोड लिखने के लिए पाश का उपयोग कर रखने के लिए और वास्तव में उस कोड को चलाने हो सकता है

In [44]: lis[0]() 
Out[44]: 0 

In [45]: lis[1]() 
Out[45]: 1 

In [46]: dis.dis(lis[0]) 
    1   0 LOAD_CONST    1 (0) 
       3 RETURN_VALUE   

In [47]: dis.dis(lis[1]) 
    1   0 LOAD_CONST    1 (1) 
       3 RETURN_VALUE   
+1

निदान सही है (यह एक बंद मुद्दा है) लेकिन कृपया 'exec' का उपयोग न करें! यह डरावना है! बुराई! बुरा! अप्रिय! –

+0

@ChrisMorgan मेरा एकमात्र लक्ष्य लैम्ब्डा को एक और तरीके से बंद करने की कोशिश करना है क्योंकि यह बार-बार आ रहा है ... 'exec' यहां अपेक्षित स्रोत कोड (ओपी के इरादे) के मेटा स्तर को चित्रित करना है। मैं लैम्बडा में डिफ़ॉल्ट तर्क का उपयोग करके सहमत हूं @ बासिकवॉल्फ के अनुसार व्याख्याओं के बाहर जाने का तरीका है। – Boud

+0

@ChrisMorgan यहां एकमात्र कामकाजी समाधान निष्पादन का उपयोग करता है। क्या आपके पास एक बेहतर सुझाव है? – kilojoules

3

@ बोउड ने एक बहुत अच्छा जवाब दिया कि यह बताते हुए कि आपका कोड काम क्यों नहीं करता है जैसा आप उम्मीद करते हैं। Baically, इससे पहले कि आप यह लैम्ब्डा में संदर्भित है i का मूल्य का मूल्यांकन करने के लिए है।

lis = [] 
for i in range(3): 
    lis.append(lambda i=i: i) 

इस का उपयोग करता है अजगर के डिफ़ॉल्ट समारोह तर्क 'मूल्यों की सुविधा है, उदाहरण के लिए: यहाँ यह करने के लिए एक सा hacky तरीका है एक समारोह में एक ने लिखा है:

def f(i=10): 
    return i 

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

j = 10 
def f(i=j): 
    return i 

j = 20 
print(f(125)) # no matter that j has been changed, the output is... 
>>> 125 

और एक ही चाल लैम्ब्डा पर लागू होती है। इसे थोड़ा स्पष्ट बनाने के लिए:

lis = [] 
for j in range(3): 
    lis.append(lambda i=j: i) 

# Calling the lambdas 
print(lis[1]()) 
>>> 1 
+0

दरअसल, डिफ़ॉल्ट तर्कों का उपयोग करना सबसे आम समाधान है मैंने देखा है। –

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