Baru-baru ini saya mulai bermain-main dengan Python dan saya menemukan sesuatu yang aneh dalam cara penutupan. Pertimbangkan kode berikut:
adders=[0,1,2,3]
for i in [0,1,2,3]:
adders[i]=lambda a: i+a
print adders[1](3)
Itu membangun array sederhana fungsi yang mengambil input tunggal dan mengembalikan input yang ditambahkan oleh angka. Fungsi-fungsi dibangun dalam for
loop di mana iterator i
berjalan dari 0
ke 3
. Untuk masing-masing angka-angka ini lambda
fungsi dibuat yang menangkap i
dan menambahkannya ke input fungsi. Baris terakhir memanggil lambda
fungsi kedua dengan 3
sebagai parameter. Yang mengejutkan saya, hasilnya adalah 6
.
Saya mengharapkan sebuah 4
. Alasan saya adalah: dalam Python semuanya adalah objek dan karenanya setiap variabel adalah penunjuk yang penting. Saat membuat lambda
closure for i
, saya berharap untuk menyimpan pointer ke objek integer yang saat ini ditunjuk oleh i
. Itu berarti bahwa ketika i
menetapkan objek integer baru itu seharusnya tidak mempengaruhi penutupan yang dibuat sebelumnya. Sayangnya, memeriksa adders
array di dalam debugger menunjukkan hal itu. Semua lambda
fungsi mengacu pada nilai terakhir i
, 3
yang mengakibatkan adders[1](3)
kembali 6
.
Yang membuat saya bertanya-tanya tentang hal berikut:
- Apa tepatnya yang ditangkap penutup?
- Apa cara paling elegan untuk meyakinkan
lambda
fungsi untuk menangkap nilai saat inii
dengan cara yang tidak akan terpengaruh ketikai
mengubah nilainya?
i
meninggalkan namespace?
print i
tidak akan berhasil setelah loop. Tapi saya mengujinya sendiri dan sekarang saya mengerti maksud Anda - itu berhasil. Saya tidak tahu bahwa variabel loop tetap setelah loop body dengan python.
if
, with
, try
dll