2009-05-08 33 views
5

Tại sao nỗ lực tạo danh sách các hàm đã kết thúc này không hoạt động?Điều gì đang xảy ra với biểu thức lambda trong hàm python này?

def p(x, num): 
    print x, num 

def test(): 
    a = [] 
    for i in range(10): 
     a.append(lambda x: p (i, x)) 
    return a 

>>> myList = test() 
>>> test[0]('test') 
9 test 
>>> test[5]('test') 
9 test 
>>> test[9]('test') 
9 test 

Điều gì đang xảy ra ở đây?

Một chức năng mà thực sự làm những gì tôi mong đợi các chức năng trên để làm là:

import functools 
def test2(): 
    a = [] 
    for i in range (10): 
     a.append(functools.partial(p, i)) 
    return a 


>>> a[0]('test') 
0 test 
>>> a[5]('test') 
5 test 
>>> a[9]('test') 
9 test 
+0

Vì bạn có một giải pháp sử dụng functools.partial, câu hỏi là gì? –

+2

Câu hỏi đặt ra là, tại sao phương pháp đầu tiên không hoạt động? – David

Trả lời

12

Trong Python, các biến được tạo ra trong các vòng lặp và các chi nhánh không được scoped. Tất cả các chức năng bạn đang tạo với lambda có tham chiếu đến cùng biến số i, được đặt thành 9 trên lần lặp cuối cùng của vòng lặp.

Giải pháp là tạo ra một hàm trả về một hàm, do đó dò tìm biến lặp. Đây là lý do tại sao phương pháp tiếp cận functools.partial() hoạt động. Ví dụ:

+0

OK. Cảm ơn rất nhiều! – David

0

Tôi đã hỏi một câu hỏi tương tự và có hai câu trả lời. Một về cơ bản giống như câu trả lời được chấp nhận ở đây, và câu trả lời khác ít rõ ràng hơn nhưng hơi khan hiếm hơn.

Dynamically creating a menu in Tkinter. (lambda expressions?)

+0

Trong đó bao gồm (và cuối cùng tôi đã hiểu bây giờ) lambda x = x: ... hack. –

1

Vâng, bạn cũng có thể ràng buộc tôi với một lambda ngoài cho lười biếng.

def p(x, num): 
    print x, num 

def test(): 
    a = [] 
    for i in range(10): 
     a.append((lambda i :lambda x: p (i, x))(i)) 
    return a 
1

Tôi luôn bị nhầm lẫn là tại sao điều này không hiệu quả. Cảm ơn bạn đã giải thích, 'a paid nerd'. Cá nhân tôi thích giải pháp này:

for i in range(10): 
    a.append(lambda num, val_i=i: p (val_i, num)) 

Lưu ý đối số val_i=i mặc định của lambda cho phép để nắm bắt những giá trị tức thời của i trong vòng lặp trong khi vẫn còn có hiệu quả làm lambda một chức năng của 1 biến. (BTW:. Thay đổi x của bạn vào num để phù hợp với p 's định nghĩa) Tôi thích nó tốt hơn vì:

  1. nó rất gần với ý tưởng ban đầu và tránh được việc phải định nghĩa một hàm có tên mới, chính xác mục đích của một lambda ...
  2. tránh nhập khẩu functools
  3. và tránh lambdas imbricating ...

Chỉ cần làm một tìm kiếm và tìm thấy lời giải thích chi tiết hơn cho cùng một vấn đề đó: Scope of python lambda functions and their parameters

+0

Các đối số được đặt tên là lý do tại sao điều này làm việc và tại sao ban đầu của bạn không. Đây là khám phá của tôi về đóng cửa bằng Python: https://gist.github.com/maxcountryman/5035489 – maxcountryman

Các vấn đề liên quan