2009-01-17 18 views
24

मैं पाइथन में स्थिरांक की सूची से लैम्ब्डा ऑब्जेक्ट्स की एक सूची बनाना चाहता हूं;मैं पाइथन लैम्बडास की सूची कैसे बना सकता हूं (एक सूची समझ/लूप के लिए)?

listOfNumbers = [1,2,3,4,5] 
square = lambda x: x * x 
listOfLambdas = [lambda: square(i) for i in listOfNumbers] 

यह जब मैं उन्हें चलाने के लिए, लैम्ब्डा वस्तुओं की एक सूची बनाने के लिए, लेकिन जाएगा: उदाहरण के लिए

for f in listOfLambdas: 
    print f(), 

मैं उम्मीद होती है कि यह

1 4 9 16 25 

इसके बजाय मुद्रित होता है, यह प्रिंट:

25 25 25 25 25 

ऐसा लगता है कि लैम्ब्डा को सभी को गलत पैरामीटर दिया गया है। क्या मैंने कुछ गलत किया है, और इसे ठीक करने का कोई तरीका है? मैं पाइथन 2.4 में हूं मुझे लगता है।

संपादित करें: 1 से 25 तक

listOfLambdas = [] 
for num in listOfNumbers: 
    action = lambda: square(num) 
    listOfLambdas.append(action) 
    print action() 

प्रिंटों की उम्मीद वर्गों, लेकिन फिर पहले प्रिंट कथन का उपयोग: चीजों की कोशिश कर के थोड़ा अधिक है और इस तरह इस के साथ आया था

for f in listOfLambdas: 
    print f(), 

अभी भी मुझे सभी 25 एस देता है। उन दो प्रिंट कॉल के बीच मौजूदा लैम्ब्डा ऑब्जेक्ट्स कैसे बदल गए?

संबंधित प्रश्न: Why results of map() and list comprehension are different?

उत्तर

17

मेरा अनुमान है कि कि लैम्ब्डा आप सूची समझ में बना रहे हैं, चर मैं जो अंततः इस प्रकार 5. पर समाप्त होता है के लिए बाध्य है, जब आप इस तथ्य के बाद lambdas का मूल्यांकन , वे सभी 5 तक बंधे हैं और 25 की गणना समाप्त कर देते हैं। वही बात आपके दूसरे उदाहरण में संख्या के साथ हो रही है। जब आप पाश अंदर लैम्ब्डा का मूल्यांकन यह संख्या ताकि आप सही मूल्य प्राप्त नहीं बदला है है। पाश के बाद, संख्या 5 है ...

मैं काफी यकीन है कि आप के लिए क्या जा रहे हैं नहीं कर रहा हूँ, तो मुझे यकीन है कि कैसे एक समाधान सुझाने के लिए नहीं कर रहा हूँ। इस बारे में कैसा है?

1 
4 
9 
16 
25 

एक और तरीका यह है के बारे में सोचना है कि एक लैम्ब्डा "कैप्चर" जहां यह बनाई गई है पर इसके शाब्दिक पर्यावरण:

def square(x): return lambda : x*x 
listOfLambdas = [square(i) for i in [1,2,3,4,5]] 
for f in listOfLambdas: print f() 

यह मैं उम्मीद उत्पादन देता है। तो, अगर आप इसे संख्या देना यह वास्तव में है कि मूल्य का समाधान नहीं होता है जब तक इसके लागू। यह दोनों भ्रामक और शक्तिशाली है।

0

मैं कभी कभी लगता है समारोह वस्तुओं के लिए वास्तविक वर्गों को परिभाषित करने से क्या समझने के लिए करता है कि क्या हो रहा है:

>>> class square(object): 
... def __init__(self, val): 
...  self.val = val 
... def __call__(self): 
...  return self.val * self.val 
... 
>>> l = [1,2,3,4,5] 
>>> funcs = [square(i) for i in l] 
>>> for f in funcs: 
... print f() 
... 
1 
4 
9 
16 
25 
>>> 

दी, ताकि उसे कुछ अतिरिक्त lambdas या बंद होने का उपयोग करने से अत्यधिक शब्द है, लेकिन मैं समझने के लिए इस आसान लगता है जब मैं कार्यों के साथ अस्पष्ट काम करने की कोशिश कर रहा हूँ।

18

आपके पास:

listOfLambdas = [lambda: i*i for i in range(6)] 

for f in listOfLambdas: 
    print f() 

आउटपुट:

25 
25 
25 
25 
25 
25 

आप currying की जरूरत है! स्वादिष्ट होने के अलावा, इस डिफ़ॉल्ट मान "हैक" का उपयोग करें।

listOfLambdas = [lambda i=i: i*i for i in range(6)] 

for f in listOfLambdas: 
    print f() 

आउटपुट:

0 
1 
4 
9 
16 
25 

नोट i=i। वह जगह है जहां जादू होता है।

+2

कूल। क्या यह "हैक" कहीं भी दस्तावेज है? क्या करी करने के लिए कोई बेहतर तरीका है? इसके अलावा, कृपया अपने घूर्णन बिस्तर को फिर से कभी भी न दें। –

+1

मैंने कभी भी इसे किसी दस्तावेज़ में स्पष्ट रूप से उल्लेख नहीं किया है। यह इस तथ्य का लाभ उठा रहा है कि फ़ंक्शन पैरामीटर के लिए डिफ़ॉल्ट मान फ़ंक्शन के निर्माण के समय असाइन किए गए हैं, जो दस्तावेज है। – recursive

+1

यह उदाहरण लगभग समान है [विभिन्न मूल्यों के साथ लूप में परिभाषित लैम्बडास एक ही परिणाम लौटाते हैं?] (Https://docs.python.org/3.4/faq/programming.html#why-do-lambdas- दस्तावेज़ों में परिभाषित-में-एक-लूप-साथ-अलग-मूल्य-सभी-वापसी-एक-परिणाम)। – abarnert

2
listOfLambdas = [lambda i=i: square(i) for i in listOfNumbers] 

या

listOfLambdas = map(lambda i: lambda: square(i), listOfNumbers) 
3

जब समारोह बयान क्रियान्वित कर रहे हैं वे अपने (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 पहचानकर्ता पास की गई चीज़ को इंगित करता है।" उस दायरे को फ़ंक्शन निष्पादन के अंत में दूर चला जाता है, जब तक कि इसके आसपास लटकने का कोई कारण न हो।

यदि आप किसी दायरे से किसी फ़ंक्शन को वापस कर रहे हैं, तो यह "स्कोप टेबल" के हिस्सों के आसपास घूमने का एक अच्छा कारण है - जो फ़ंक्शन आप लौट रहे हैं वह उस स्कोप टेबल से चीजों को संदर्भित कर सकता है जब आप इसे कॉल करते हैं बाद में। इसी कारण से, funget_fun के भीतर बनाया गया है पाइथन funget_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>,) 
1

कोशिश (: ऊपर में, हम जो एक पूर्णांक होता value के संदर्भ में, देखने के

listOfLambdas = (lambda: square(i) for i in listOfNumbers) 

और आप मिल जाएगा:

1 
4 
9 
16 
25 
0

तुम भी कर सकता है:

>>> def squares(): 
...  for i in [1,2,3,4,5]: 
...   yield lambda:i*i 
... 
>>> print [square() for square in squares()] 
[1, 4, 9, 16, 25] 
0

एक अतिरिक्त टिप्पणी के रूप में, मैं sympy matrices से लैम्ब्डा कार्यों की सूचियां उत्पन्न करने की संभावना को रेखांकित करना चाहता हूं (मुझे नहीं पता कि यह करने का सबसे अच्छा तरीका है, लेकिन मैं ऐसा करता हूं और मुझे यह सुविधाजनक लगता है) :

import sympy as sp 
sp.var('Ksi') 
# generate sympy expressions for Berstein's polynomials 
B_expr = sp.Matrix([sp.binomial(3, i) * Ksi**i * (1 - Ksi)**(3-i) for i in range(4)]) 
# lambdify them 
B = [sp.lambdify((Ksi), B_expr[i]) for i in range(4) ] 
संबंधित मुद्दे

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