2009-07-10 39 views
14

Điều gì đang xảy ra ở đây? Tôi đang cố gắng tạo danh sách các chức năng:Các vấn đề về Python Lambda

def f(a,b): 
    return a*b 

funcs = [] 

for i in range(0,10): 
    funcs.append(lambda x:f(i,x)) 

Điều này không làm những gì tôi mong đợi. Tôi mong chờ danh sách để hành động như thế này:

funcs[3](3) = 9 
funcs[0](5) = 0 

Nhưng tất cả các chức năng trong danh sách dường như giống hệt nhau, và được thiết lập các giá trị cố định là 9:

funcs[3](3) = 27 
funcs[3](1) = 9 

funcs[2](6) = 54 

Bất kỳ ý tưởng?

Trả lời

18

lambdas trong python là đóng cửa .... các đối số bạn cho nó aren' sẽ được đánh giá cho đến khi lambda được đánh giá. Vào thời điểm đó, i = 9 bất kể, bởi vì quá trình lặp của bạn đã kết thúc.

Các hành vi bạn đang tìm kiếm có thể đạt được với functools.partial

import functools 

def f(a,b): 
    return a*b 

funcs = [] 

for i in range(0,10): 
    funcs.append(functools.partial(f,i)) 
+0

Điều đó phải là functools.partial (f, i) – FogleBird

+0

Tôi đồng ý.Ứng dụng một phần là cách để đi đến đây. –

+0

ở đây một phần (f, i) là viết tắt của một phần (f, b = i) không phải là một phần (f, a = i). vì vậy nó không giống với bài gốc. Ứng dụng chức năng một phần 'từ bên phải' (http://www.gossamer-threads.com/lists/python/dev/715103) đã bị từ chối hai lần. – sunqiang

2

Xét giá trị cuối cùng của i == 9

Giống như bất kỳ chức năng python tốt, nó sẽ sử dụng giá trị của biến trong phạm vi nó được xác định. Có lẽ lambda: varname (là nó là một ngôn ngữ xây dựng) liên kết với tên, không phải là giá trị, và đánh giá tên đó trong thời gian chạy?

Tương tự như:

i = 9 
def foo(): 
    print i 

i = 10 
foo() 

Tôi muốn được khá quan tâm đến việc tìm ra câu trả lời của tôi là đúng

10

Chỉ có một i đó là ràng buộc với nhau lambda, trái với những gì bạn nghĩ. Đây là một sai lầm phổ biến.

Một cách để có được những gì bạn muốn là:

for i in range(0,10): 
    funcs.append(lambda x, i=i: f(i, x)) 

Bây giờ bạn đang tạo một tham số mặc định i trong từng đóng lambda và ràng buộc với nó giá trị hiện của vòng lặp biến i.

13

Đúng, "vấn đề phạm vi" thông thường (thực sự là vấn đề ràng buộc-sau-hơn-bạn muốn, nhưng nó thường được gọi bằng tên đó). Bạn đã nhận được hai câu trả lời hay nhất (vì đơn giản nhất) - giải pháp "mặc định giả" i=ifunctools.partial, vì vậy tôi chỉ đưa ra giải pháp thứ ba của ba cổ điển, "nhà máy lambda":

for i in range(0,10): 
    funcs.append((lambda i: lambda x: f(i, x))(i)) 

Cá nhân tôi muốn đi với i=i nếu không có nguy cơ nào trong các hàm funcs vô tình được gọi với 2 tham số thay vì chỉ 1, nhưng cách tiếp cận chức năng của nhà máy đáng xem xét khi bạn cần thứ gì đó phong phú hơn một chút so với trước ràng buộc một arg.

+2

Tôi chưa từng thấy cái này trước đây. Loại gọn gàng. – ars

+0

@ars, bit của một overkill cho hầu hết các trường hợp thực sự (trong Python), nhưng nó là một trong những gì tự nhiên sẽ làm trong (nói) Đề án, vì vậy tôi đoán nó _is_ kinda gọn ;-). –

+0

Đúng vậy, tôi không thể nghĩ ngay về một trường hợp mà tôi thích nó, nhưng dù sao cũng là một công trình thú vị. :-) – ars