Pertanyaan ini menyentuh bagian yang sangat busuk dari sintaksis Python "terkenal" dan "jelas" - apa yang diutamakan, lambda, atau untuk pemahaman daftar.
Saya tidak berpikir tujuan OP adalah untuk menghasilkan daftar kotak dari 0 hingga 9. Jika itu masalahnya, kami dapat memberikan lebih banyak solusi:
squares = []
for x in range(10): squares.append(x*x)
- ini adalah cara sintaksis imperatif yang baik.
Tapi bukan itu intinya. Intinya adalah W (hy) TF apakah ekspresi ambigu ini begitu kontra-intuitif? Dan saya punya kasus idiot untuk Anda pada akhirnya, jadi jangan abaikan jawaban saya terlalu dini (saya sudah ada di wawancara kerja).
Jadi, pemahaman OP mengembalikan daftar lambda:
[(lambda x: x*x) for x in range(10)]
Ini tentu saja hanya 10 salinan berbeda dari fungsi kuadrat, lihat:
>>> [lambda x: x*x for _ in range(3)]
[<function <lambda> at 0x00000000023AD438>, <function <lambda> at 0x00000000023AD4A8>, <function <lambda> at 0x00000000023AD3C8>]
Catat alamat memori dari lambda - semuanya berbeda!
Anda tentu saja dapat memiliki versi yang lebih "optimal" (haha) dari ungkapan ini:
>>> [lambda x: x*x] * 3
[<function <lambda> at 0x00000000023AD2E8>, <function <lambda> at 0x00000000023AD2E8>, <function <lambda> at 0x00000000023AD2E8>]
Lihat? 3 kali lambda yang sama .
Harap dicatat, bahwa saya digunakan _sebagaifor variabel. Ini tidak ada hubungannya dengan xdi lambda(itu dibayangi secara leksikal!). Mengerti?
Saya meninggalkan diskusi, mengapa prioritas sintaksinya tidak begitu, bahwa itu semua berarti:
[lambda x: (x*x for x in range(10))]
yang bisa berupa:, [[0, 1, 4, ..., 81]]atau [(0, 1, 4, ..., 81)], atau yang menurut saya paling logis , ini akan menjadi listelemen 1 - agenerator mengembalikan nilai. Bukan itu masalahnya, bahasanya tidak bekerja seperti ini.
TAPI Apa, Jika ...
Bagaimana jika Anda TIDAK menaungi forvariabel, DAN menggunakannya dalam file Anda lambda???
Nah, kemudian omong kosong terjadi. Lihat ini:
[lambda x: x * i for i in range(4)]
ini tentu saja berarti:
[(lambda x: x * i) for i in range(4)]
TETAPI TIDAK BERARTI:
[(lambda x: x * 0), (lambda x: x * 1), ... (lambda x: x * 3)]
Ini gila!
Lambda dalam daftar pemahaman adalah penutupan atas ruang lingkup pemahaman ini. Sebuah leksikal penutupan, sehingga mereka mengacu padai melalui referensi, dan tidak nilainya ketika mereka dievaluasi!
Jadi, ungkapan ini:
[(lambda x: x * i) for i in range(4)]
Kira-kira SETARA untuk:
[(lambda x: x * 3), (lambda x: x * 3), ... (lambda x: x * 3)]
Saya yakin kita bisa melihat lebih banyak di sini menggunakan decompiler python (yang saya maksud misalnya dis modul), tetapi untuk diskusi Python-VM-agnostik ini sudah cukup. Begitu banyak untuk pertanyaan wawancara kerja.
Sekarang, bagaimana membuat listlambda multiplier, yang benar-benar dikalikan dengan integer berturut-turut? Nah, mirip dengan jawaban yang diterima, kita perlu memutuskan hubungan langsung idengan membungkusnya dengan yang lain lambda, yang dipanggil ke dalam dalam ekspresi daftar pemahaman:
Sebelum:
>>> a = [(lambda x: x * i) for i in (1, 2)]
>>> a[1](1)
2
>>> a[0](1)
2
Setelah:
>>> a = [(lambda y: (lambda x: y * x))(i) for i in (1, 2)]
>>> a[1](1)
2
>>> a[0](1)
1
(Saya memiliki variabel lambda luar juga = i, tapi saya memutuskan ini adalah solusi yang lebih jelas - saya perkenalkany agar kita semua bisa melihat penyihir mana yang mana).
Edit 2019-08-30:
Mengikuti saran oleh @josoler, yang juga hadir dalam jawaban oleh @sheridp - nilai dari daftar pemahaman "variabel loop" dapat "tertanam" di dalam suatu objek - kuncinya adalah untuk diakses pada waktu yang tepat. Bagian "Setelah" di atas melakukannya dengan membungkusnya dengan yang lain lambdadan memanggilnya segera dengan nilai saat ini dari i. Cara lain (sedikit lebih mudah dibaca - tidak menghasilkan efek 'WAT') adalah untuk menyimpan nilai idi dalam partialobjek, dan meminta "inner" (asli) lambdamenganggapnya sebagai argumen (disahkan olehpartial objek di waktu panggilan), yaitu:
Setelah 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)
Hebat, tetapi masih ada sedikit twist untuk Anda! Katakanlah kita tidak ingin membuatnya lebih mudah pada pembaca kode, dan meneruskan faktor dengan nama (sebagai argumen kata kunci ke partial). Mari kita lakukan penggantian nama:
Setelah 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'
WAT?
>>> a[0]()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: <lambda>() missing 1 required positional argument: 'x'
Tunggu ... Kami mengubah jumlah argumen dengan 1, dan beralih dari "terlalu banyak" menjadi "terlalu sedikit"?
Yah, itu bukan WAT asli, ketika kita masuk coefdengan partialcara ini, itu menjadi argumen kata kunci, jadi harus muncul setelah xargumen posisi , seperti:
Setelah 3:
>>> a = [partial(lambda x, coef: coef * x, coef=i) for i in (1, 2)]
>>> a[0](2), a[1](2)
(2, 4)
Saya lebih suka versi terakhir daripada lambda bersarang, tetapi untuk masing-masing ...
[lambda x: x*x for x in range(10)]lebih cepat dari yang pertama, karena tidak memanggil fungsi loop luar, f berulang kali.