Mengapa output dari dua berikut daftar comprehensions berbeda, meskipun f
dan lambda
fungsi yang sama?
f = lambda x: x*x
[f(x) for x in range(10)]
dan
[lambda x: x*x for x in range(10)]
Pikiran Anda, keduanya type(f)
dan type(lambda x: x*x)
kembali jenis yang sama.
[lambda x: x*x for x in range(10)]
lebih cepat dari yang pertama, karena tidak memanggil fungsi loop luar, f berulang kali.[x*x for x in range(10)]
lebih baik.Jawaban:
Yang pertama membuat fungsi lambda tunggal dan menyebutnya sepuluh kali.
Yang kedua tidak memanggil fungsi. Ini menciptakan 10 fungsi lambda berbeda. Semua itu ada dalam daftar. Untuk membuatnya setara dengan yang pertama yang Anda butuhkan:
Atau lebih baik lagi:
sumber
map(lambda x: x*x, range(10))
, yang mungkin merupakan arti OP pada awalnya.list(map(lambda x: x*x, range(10)))
akan memberi Anda[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
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:
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:
Ini tentu saja hanya 10 salinan berbeda dari fungsi kuadrat, lihat:
Catat alamat memori dari lambda - semuanya berbeda!
Anda tentu saja dapat memiliki versi yang lebih "optimal" (haha) dari ungkapan ini:
Lihat? 3 kali lambda yang sama .
Harap dicatat, bahwa saya digunakan
_
sebagaifor
variabel. Ini tidak ada hubungannya denganx
dilambda
(itu dibayangi secara leksikal!). Mengerti?Saya meninggalkan diskusi, mengapa prioritas sintaksinya tidak begitu, bahwa itu semua berarti:
yang bisa berupa:,
[[0, 1, 4, ..., 81]]
atau[(0, 1, 4, ..., 81)]
, atau yang menurut saya paling logis , ini akan menjadilist
elemen 1 - agenerator
mengembalikan nilai. Bukan itu masalahnya, bahasanya tidak bekerja seperti ini.TAPI Apa, Jika ...
Bagaimana jika Anda TIDAK menaungi
for
variabel, DAN menggunakannya dalam file Andalambda
???Nah, kemudian omong kosong terjadi. Lihat ini:
ini tentu saja berarti:
TETAPI TIDAK BERARTI:
Ini gila!
Lambda dalam daftar pemahaman adalah penutupan atas ruang lingkup pemahaman ini. Sebuah leksikal penutupan, sehingga mereka mengacu pada
i
melalui referensi, dan tidak nilainya ketika mereka dievaluasi!Jadi, ungkapan ini:
Kira-kira SETARA untuk:
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
list
lambda multiplier, yang benar-benar dikalikan dengan integer berturut-turut? Nah, mirip dengan jawaban yang diterima, kita perlu memutuskan hubungan langsungi
dengan membungkusnya dengan yang lainlambda
, yang dipanggil ke dalam dalam ekspresi daftar pemahaman:Sebelum:
Setelah:
(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
lambda
dan memanggilnya segera dengan nilai saat ini darii
. Cara lain (sedikit lebih mudah dibaca - tidak menghasilkan efek 'WAT') adalah untuk menyimpan nilaii
di dalampartial
objek, dan meminta "inner" (asli)lambda
menganggapnya sebagai argumen (disahkan olehpartial
objek di waktu panggilan), yaitu:Setelah 2:
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:
WAT?
Tunggu ... Kami mengubah jumlah argumen dengan 1, dan beralih dari "terlalu banyak" menjadi "terlalu sedikit"?
Yah, itu bukan WAT asli, ketika kita masuk
coef
denganpartial
cara ini, itu menjadi argumen kata kunci, jadi harus muncul setelahx
argumen posisi , seperti:Setelah 3:
Saya lebih suka versi terakhir daripada lambda bersarang, tetapi untuk masing-masing ...
sumber
[partial(lambda i, x: i * x, i) for i in (1, 2)]
Perbedaan besar adalah bahwa contoh pertama benar-benar memanggil lambda
f(x)
, sedangkan contoh kedua tidak.Contoh pertama Anda sama dengan
[(lambda x: x*x)(x) for x in range(10)]
sedangkan contoh kedua Anda sama dengan[f for x in range(10)]
.sumber
Yang pertama
berjalan
f()
untuk setiap nilai dalam rentang sehinggaf(x)
untuk setiap nilaiyang kedua
menjalankan lambda untuk setiap nilai dalam daftar, sehingga menghasilkan semua fungsi tersebut.
sumber
Orang-orang memberikan jawaban yang baik tetapi lupa menyebutkan bagian terpenting menurut saya: Pada contoh kedua
X
, pemahaman daftar BUKAN samaX
denganlambda
fungsi, mereka sama sekali tidak berhubungan. Jadi contoh kedua sebenarnya sama dengan:Iterasi internal aktif
range(10)
hanya bertanggung jawab untuk membuat 10 fungsi lambda serupa dalam daftar (10 fungsi terpisah tetapi sama sekali sama - mengembalikan kekuatan 2 dari setiap input).Di sisi lain, contoh pertama bekerja sangat berbeda, karena X dari iterasi DO berinteraksi dengan hasil, untuk setiap iterasi nilainya
X*X
jadi hasilnya akan menjadi[0,1,4,9,16,25, 36, 49, 64 ,81]
sumber
Jawaban lainnya benar, tetapi jika Anda mencoba membuat daftar fungsi, masing-masing dengan parameter yang berbeda, yang dapat dieksekusi nanti , kode berikut akan melakukannya:
Sementara contoh dibuat, saya menemukan itu berguna ketika saya ingin daftar fungsi yang masing-masing mencetak sesuatu yang berbeda, yaitu
sumber