2011-09-22 35 views
6

cuộc đàm phán tiếp Mã:hàm lambda không đóng tham số trong Python?


from pprint import pprint 

li = [] 

for i in range(5): 
     li.append(lambda : pprint(i)) 

for k in li: 
     k() 

năng suất:

 
4 
4 
4 
4 
4 

tại sao không

 
0 
1 
2 
3 
4 

??

Cảm ơn.

P.S. Nếu tôi viết trang trí hoàn chỉnh, nó hoạt động như mong đợi:



from pprint import pprint 

li = [] 

#for i in range(5): 
     #li.append(lambda : pprint(i)) 

def closure(i): 
     def _func(): 
       pprint(i) 
     return _func 

for i in range(5): 
     li.append(closure(i)) 

for k in li: 
     k() 
+0

xem [câu hỏi này] (http://stackoverflow.com/q/2295290/195823) và [câu trả lời của tôi cho câu hỏi này] (http://stackoverflow.com/questions/2295290/what-do-lambda- function-closures-capture-in-python/2295372 # 2295372) –

+0

Bạn có thể thấy đó là đóng biến bằng cách di chuyển vòng lặp ban đầu vào một hàm, và sau đó gọi hàm trước dòng 'for k in li:', vì vậy rằng 'i' không phải là tên hợp lệ trong phạm vi cấp mô-đun. Nó sẽ vẫn hoạt động (và nhận được kết quả tương tự vì nó đóng một tham chiếu không phải là giá trị), có nghĩa là tên được đóng lại. – agf

+0

Cảm ơn tất cả các bạn.Tôi nghĩ rằng http://stackoverflow.com/questions/2295290/what-do-lambda-function-closures-capture-in-python/2295368#2295368 không chỉ giải thích mà còn lý do tại sao. Tôi nghĩ câu hỏi của tôi trùng lặp với http://stackoverflow.com/questions/2295290/what-do-lambda-function-closures-capture-in-python – Grissiom

Trả lời

10

bạn cần làm:

lambda i=i: pprint(i) 

thay vì để nắm bắt những giá trị hiện tại của i

3

Nó tham khảo đúng i, chỉ điều này là do thời gian danh sách của bạn được điền, i sẽ có giá trị được chỉ định làm mục cuối cùng trong chuỗi khi lặp lại kết thúc, vì vậy đó là lý do tại sao bạn thấy 4 trên tất cả.

0

Hàm lambda tạo các bao đóng trên biến số i. Sau khi kết thúc for vòng lặp đầu tiên, i có giá trị 4.

Sau đó, vòng lặp for thứ hai bắt đầu và tất cả các hàm lambda được thực hiện. Mỗi người trong số họ sau đó in giá trị hiện tại của i, là 4.

3

Nếu bạn không muốn sử dụng một đối số mặc định - điều này có thể giới thiệu các lỗi nếu vô tình gọi với một cuộc tranh cãi - bạn có thể sử dụng một lambda lồng nhau:

from pprint import pprint 

li = [] 

for i in range(5): 
    li.append((lambda x: lambda: pprint(x))(i)) 

for k in li: 
    k() 

Đây là phiên bản mang tính chất của bạn Hàm closure.

0

Câu trả lời: Vì mã bên trong lambda đang sử dụng biến toàn cầu của bạn i.

biến thể thứ hai của bạn sẽ làm tương tự như một trong những đầu tiên với lambda nếu bạn loại bỏ các tham số i:

def closure(): 

Thay vì

def closure(i): 

Tức là mã bên trong hàm sẽ sử dụng biến toàn cầu i.

+0

Nó không liên quan gì đến phạm vi của biến, đó là sự kiện rằng những gì được đóng lại là một tham chiếu đến một giá trị chứ không phải là một giá trị. Xem chú thích của tôi cho câu hỏi - nếu bạn di chuyển vòng lặp 'for i in range' thành một hàm, vì vậy' i' không tồn tại trong phạm vi toàn cục, sau đó gọi hàm này trước vòng lặp 'for k in li', sẽ cho cùng một câu trả lời. – agf

+0

> nếu bạn di chuyển cho i trong phạm vi vòng lặp vào một hàm, vì vậy tôi không tồn tại trong phạm vi toàn cục, sau đó gọi hàm trước k cho vòng lặp li, nó sẽ trả lời cùng ... --- ie không phải địa phương? Đó là điều tôi muốn nói. – warvariuc

+0

nó đang tìm biến 'i'. vì không có đối số hàm 'i' nó có biến' i' từ phạm vi bên ngoài. – warvariuc

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