2010-12-13 42 views
5

Tôi đã mã python sau đó tạo ra một danh sách các hàm nặc danh:Tạo một danh sách các chức năng trong python

basis = [ (lambda x: n*x) for n in [0, 1, 2] ]  
print basis[0](1) 

tôi lại có thể ngờ nó là tương đương với

basis = [ (lambda x: 0*x), (lambda x: 1*x), (lambda x: 2*x) ] 
print basis[0](1) 

Tuy nhiên, trong khi đoạn thứ hai in ra 0 đó là những gì tôi mong đợi, các bản in đầu tiên 2. Có gì sai với đoạn mã đầu tiên, và tại sao nó không hoạt động như mong đợi?

+0

câu hỏi liên quan: http://stackoverflow.com/q/139819/4279 – jfs

Trả lời

8

Bạn có thể sử dụng một tham số mặc định để tạo ra một đóng cửa trên n

>>> basis = [ (lambda x,n=n: n*x) for n in [0, 1, 2] ]  
>>> print basis[0](1) 
0 
+3

Kỹ thuật này thường được sử dụng để chuyển các phương thức như hàm gọi lại. Nó trông giống như 'register_event_handler (event = evt, callback = lambda cbVar1, cbVar2, s = self: s.handle_evt (cbVar1, cbVar2))'. –

2

Vấn đề là trong ví dụ đầu tiên, mỗi lambda được liên kết với cùng một n - nói cách khác, nó đang nắm bắt biến, không phải là giá trị của biến. Vì n có giá trị là 2 ở cuối vòng lặp, mỗi lambda đang sử dụng giá trị 2 cho n.

Rõ ràng bạn có thể sử dụng các thông số mặc định để giải quyết vấn đề này:

basis = [ (lambda x,n=n: n*x) for n in [0, 1, 2] ] 
print basis[0](1) 

Kể từ khi giá trị tham số mặc định là hằng số, các n ở phía bên phải của n=n sẽ được đánh giá mỗi lần qua vòng lặp để cung cấp cho bạn một mới giá trị được ghi lại.

+0

Bất kỳ đề xuất về cách sửa lỗi đó? – dzhelil

+1

celil: Tôi đã chỉnh sửa câu trả lời của mình để đưa ra đề xuất khắc phục, nhưng nó không phải là rất thanh lịch. – Gabe

+0

Các tham số mặc định có thể không thanh lịch, nhưng chúng dễ dàng hơn nhiều so với đánh giá một phần rõ ràng như tôi đã từng làm: 'base = [(lambda n: (lambda x: n * x)) (n) cho n trong phạm vi (3)] '. :/Tham số mặc định không phải là "hằng số" theo nghĩa là không thay đổi, nhưng nó được đánh giá và liên kết trong '.func_defaults' của lambda. Các thông số đóng cũng làm như vậy, nhưng rõ ràng theo một cách kỳ diệu hơn ... –

3

Vì đó là "truyền theo tên".

Đó là, khi lambda được chạy, nó thực thi n*x: x là ràng buộc để 1 (nó là một tham số), n được ngẩng đầu lên trong môi trường (nó là tại 2). Vì vậy, kết quả là 2.

+0

Điều này không giải thích lý do tại sao cùng một hành vi được trưng bày khi chúng ta sử dụng một máy phát hiểu để thay thế, mà không "rò rỉ" 'n' vào' local() '. AFAICT, giá trị của 'n' được tra cứu từ' .func_closure' của lambda, và nó không hoàn toàn rõ ràng về cách kỳ diệu này ám chỉ đến bất kỳ 'n' cuối cùng được gọi khi' n' không tồn tại nữa. –

0

Tôi muốn giúp đỡ với sự hiểu biết về những nhận xét từ Karl Knechtel (13 tháng 12 '10 lúc 7 : 32). Các mã sau đây cho thấy cách sử dụng máy phát điện, định nghĩa lambda gốc cung cấp cho các kết quả dự kiến, nhưng nó không sử dụng danh sách hoặc tuple:

>>> #GENERATOR 
... basis = ((lambda x: n*x) for n in [0, 1, 2]) 
>>> print(type(basis)) 
<type 'generator'> 
>>> basis = ((lambda x: n*x) for n in [0, 1, 2]) 
>>> print([x(3) for x in basis]) 
[0, 3, 6] 
>>> #TUPLE 
... basis = tuple((lambda x: n*x) for n in [0, 1, 2]) 
>>> print(type(basis)) 
<type 'tuple'> 
>>> print([x(3) for x in basis]) 
[6, 6, 6] 
>>> #LIST 
... basis = list((lambda x: n*x) for n in [0, 1, 2]) 
>>> print(type(basis)) 
<type 'list'> 
>>> print([x(3) for x in basis]) 
[6, 6, 6] 
>>> #CORRECTED LIST 
... basis = list((lambda x, n=n: n*x) for n in [0, 1, 2]) 
>>> print(type(basis)) 
<type 'list'> 
>>> print([x(3) for x in basis]) 
[0, 3, 6] 
Các vấn đề liên quan