Câu hỏi này chạm vào một phần rất hôi thối của cú pháp Python "nổi tiếng" và "rõ ràng" - điều được ưu tiên, lambda hoặc để hiểu danh sách.
Tôi không nghĩ mục đích của OP là tạo ra một danh sách các ô vuông từ 0 đến 9. Nếu đó là trường hợp, chúng tôi có thể đưa ra nhiều giải pháp hơn nữa:
squares = []
for x in range(10): squares.append(x*x)
- đây là cách tốt của cú pháp mệnh lệnh.
Nhưng nó không phải là vấn đề. Vấn đề là W (hy) TF có phải là biểu hiện mơ hồ như vậy phản trực giác? Và tôi có một trường hợp ngu ngốc cho bạn vào cuối, vì vậy đừng bỏ qua câu trả lời của tôi quá sớm (tôi đã có nó trong một cuộc phỏng vấn xin việc).
Vì vậy, sự hiểu biết của OP đã trả về một danh sách lambdas:
[(lambda x: x*x) for x in range(10)]
Tất nhiên đây chỉ là 10 bản sao khác nhau của hàm bình phương, xem:
>>> [lambda x: x*x for _ in range(3)]
[<function <lambda> at 0x00000000023AD438>, <function <lambda> at 0x00000000023AD4A8>, <function <lambda> at 0x00000000023AD3C8>]
Lưu ý các địa chỉ bộ nhớ của lambdas - tất cả chúng đều khác nhau!
Tất nhiên bạn có thể có phiên bản "tối ưu" (haha) hơn của biểu thức này:
>>> [lambda x: x*x] * 3
[<function <lambda> at 0x00000000023AD2E8>, <function <lambda> at 0x00000000023AD2E8>, <function <lambda> at 0x00000000023AD2E8>]
Xem? 3 lần cùng lambda.
Xin lưu ý rằng tôi đã sử dụng _như là forbiến. Nó không có gì để làm với xtrong lambda(nó bị lu mờ lexically!). Hiểu rồi?
Tôi đang rời khỏi cuộc thảo luận, tại sao ưu tiên cú pháp không phải như vậy, tất cả đều có nghĩa là:
[lambda x: (x*x for x in range(10))]
có thể là : [[0, 1, 4, ..., 81]], hoặc [(0, 1, 4, ..., 81)], hoặc tôi thấy hợp lý nhất , đây sẽ là một listtrong 1 phần tử - generatortrả về các giá trị. Nó không phải là trường hợp, ngôn ngữ không hoạt động theo cách này.
NHƯNG GÌ, Nếu ...
Điều gì sẽ xảy ra nếu bạn không làm lu mờ forbiến và VÀ sử dụng nó trong lambdas ???
Vâng, sau đó tào lao xảy ra. Nhìn vào cái này
[lambda x: x * i for i in range(4)]
điều này có nghĩa là tất nhiên:
[(lambda x: x * i) for i in range(4)]
NHƯNG nó không có nghĩa là:
[(lambda x: x * 0), (lambda x: x * 1), ... (lambda x: x * 3)]
Điều này thật điên rồ!
Các lambdas trong việc hiểu danh sách là một đóng cửa trong phạm vi của sự hiểu biết này. Một đóng cửa từ vựng , vì vậy họ tham chiếu iqua tham chiếu, và không phải giá trị của nó khi chúng được đánh giá!
Vì vậy, biểu thức này:
[(lambda x: x * i) for i in range(4)]
IS đại khái là:
[(lambda x: x * 3), (lambda x: x * 3), ... (lambda x: x * 3)]
Tôi chắc rằng chúng ta có thể thấy nhiều hơn ở đây bằng cách sử dụng trình dịch ngược python (ý tôi là ví dụ như dismô-đun), nhưng đối với thảo luận về thuyết bất khả tri của Python-VM thì điều này là đủ. Quá nhiều cho câu hỏi phỏng vấn xin việc.
Bây giờ, làm thế nào để tạo ra một listsố nhân lambdas, mà thực sự nhân với số nguyên liên tiếp? Vâng, tương tự như câu trả lời được chấp nhận, chúng ta cần phá vỡ mối quan hệ trực tiếp ibằng cách gói nó vào một câu trả lời khác lambda, được gọi trong biểu thức hiểu danh sách:
Trước:
>>> a = [(lambda x: x * i) for i in (1, 2)]
>>> a[1](1)
2
>>> a[0](1)
2
Sau:
>>> a = [(lambda y: (lambda x: y * x))(i) for i in (1, 2)]
>>> a[1](1)
2
>>> a[0](1)
1
(Tôi cũng có biến lambda bên ngoài = i, nhưng tôi quyết định đây là giải pháp rõ ràng hơn - tôi đã giới thiệu yđể tất cả chúng ta có thể thấy phù thủy nào là phù hợp).
Chỉnh sửa 2019-08-30:
Theo gợi ý của @josoler, cũng có mặt trong câu trả lời của @sheridp - giá trị của "vòng lặp" hiểu danh sách có thể được "nhúng" vào bên trong một đối tượng - khóa được truy cập vào đúng thời điểm. Phần "Sau" ở trên thực hiện bằng cách gói nó vào phần khác lambdavà gọi nó ngay lập tức với giá trị hiện tại là i. Một cách khác (dễ đọc hơn một chút - nó không tạo ra hiệu ứng 'WAT') là lưu trữ giá trị ibên trong một partialđối tượng và để "bên trong" (bản gốc) lambdalấy nó làm đối số (được cung cấp bởi partialđối tượng tại thời gian của cuộc gọi), tức là:
Sau 2:
>>> from functools import partial
>>> a = [partial(lambda y, x: y * x, i) for i in (1, 2)]
>>> a[0](2), a[1](2)
(2, 4)
Tuyệt vời, nhưng vẫn có một chút thay đổi cho bạn! Giả sử chúng ta sẽ không làm cho trình đọc mã dễ dàng hơn và chuyển yếu tố theo tên (làm đối số từ khóa cho partial). Chúng ta hãy đổi tên:
Sau 2,5:
>>> a = [partial(lambda coef, x: coef * x, coef=i) for i in (1, 2)]
>>> a[0](1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: <lambda>() got multiple values for argument 'coef'
BÌNH THƯỜNG?
>>> a[0]()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: <lambda>() missing 1 required positional argument: 'x'
Đợi đã ... Chúng ta sẽ thay đổi số lượng đối số bằng 1 và chuyển từ "quá nhiều" sang "quá ít"?
Chà, nó không phải là một LỚN thực sự, khi chúng ta chuyển coefsang partialtheo cách này, nó trở thành một đối số từ khóa, vì vậy nó phải xuất hiện sau xđối số vị trí , như vậy:
Sau 3:
>>> a = [partial(lambda x, coef: coef * x, coef=i) for i in (1, 2)]
>>> a[0](2), a[1](2)
(2, 4)
Tôi thích phiên bản cuối cùng hơn lambda lồng nhau, nhưng với mỗi ...
[lambda x: x*x for x in range(10)]nhanh hơn cái đầu tiên, vì nó không gọi hàm vòng lặp bên ngoài, f lặp đi lặp lại.