Pemahaman mengalami beberapa interaksi tak terduga dengan pelingkupan. Apakah ini perilaku yang diharapkan?
Saya punya metode:
def leave_room(self, uid):
u = self.user_by_id(uid)
r = self.rooms[u.rid]
other_uids = [ouid for ouid in r.users_by_id.keys() if ouid != u.uid]
other_us = [self.user_by_id(uid) for uid in other_uids]
r.remove_user(uid) # OOPS! uid has been re-bound by the list comprehension above
# Interestingly, it's rebound to the last uid in the list, so the error only shows
# up when len > 1
Dengan risiko merengek, ini adalah sumber kesalahan yang brutal. Saat saya menulis kode baru, saya hanya sesekali menemukan kesalahan yang sangat aneh karena pengikatan ulang - bahkan sekarang saya tahu itu masalah. Saya perlu membuat aturan seperti "selalu awali temp vars dalam pemahaman daftar dengan garis bawah", tetapi itu pun bukan bukti yang bodoh.
Fakta bahwa ada semacam menunggu bom waktu acak ini meniadakan semua "kemudahan penggunaan" dari pemahaman daftar.
python
binding
list-comprehension
Jabavu Adams
sumber
sumber
for
membangun -loop danfor
-loops variabel kebocoran . Jadi itu tidak eksplisit tetapi dinyatakan secara implisit.Jawaban:
Pemahaman daftar membocorkan variabel kontrol loop di Python 2 tetapi tidak di Python 3. Berikut Guido van Rossum (pencipta Python) yang menjelaskan sejarah di balik ini:
sumber
break
- tetapi tidak relevan dengan pemahaman. Saya ingat beberapa diskusi comp.lang.python di mana orang ingin menetapkan variabel di tengah ekspresi. Cara yang kurang gila yang ditemukan adalah nilai tunggal untuk klausa mis.sum100 = [s for s in [0] for i in range(1, 101) for s in [s + i]][-1]
, tetapi hanya membutuhkan pemahaman-lokal var dan bekerja dengan baik di Python 3. Saya pikir "bocor" adalah satu-satunya cara untuk mengatur variabel terlihat di luar ekspresi. Semua orang setuju bahwa teknik ini mengerikan :-)Ya, daftar pemahaman "membocorkan" variabel mereka dengan Python 2.x, seperti untuk loop.
Dalam retrospeksi, ini dikenali sebagai kesalahan, dan itu dihindari dengan ekspresi generator. EDIT: Seperti yang dicatat Matt B. itu juga dihindari ketika sintaks pemahaman set dan kamus di-backport dari Python 3.
Perilaku pemahaman daftar harus dibiarkan seperti pada Python 2, tetapi sepenuhnya diperbaiki dalam Python 3.
Ini berarti bahwa di semua:
the
x
selalu lokal untuk ekspresi sementara ini:dengan Python 2.x semua membocorkan
x
variabel ke lingkup sekitarnya.UPDATE untuk Python 3.8 (?) : PEP 572 akan memperkenalkan
:=
operator penugasan yang sengaja bocor keluar dari pemahaman dan ekspresi generator! Ini pada dasarnya dimotivasi oleh 2 kasus penggunaan: menangkap "saksi" dari fungsi penghentian awal sepertiany()
danall()
:dan memperbarui status yang bisa berubah:
Lihat Lampiran B untuk pelingkupan yang tepat. Variabel ditempatkan di sekitar terdekat
def
ataulambda
, kecuali fungsi itu mendeklarasikannyanonlocal
atauglobal
.sumber
Ya, penugasan dilakukan di sana, seperti yang akan terjadi di file
for
putaran. Tidak ada cakupan baru yang sedang dibuat.Ini jelas merupakan perilaku yang diharapkan: pada setiap siklus, nilainya terikat pada nama yang Anda tentukan. Misalnya,
Setelah dikenali, tampaknya cukup mudah untuk dihindari: jangan gunakan nama yang ada untuk variabel dalam pemahaman.
sumber
Menariknya, ini tidak memengaruhi kamus atau pemahaman himpunan.
Namun telah diperbaiki dalam 3 seperti disebutkan di atas.
sumber
beberapa solusi, untuk python 2.6, jika perilaku ini tidak diinginkan
sumber
Di python3 sementara dalam pemahaman daftar, variabel tidak mendapatkan perubahan setelah cakupannya berakhir tetapi ketika kita menggunakan perulangan sederhana variabel tersebut dipindahkan ke luar cakupan.
i = 1 cetakan (i) cetakan ([i dalam kisaran (5)]) cetakan (i) Nilai i akan tetap 1 saja.
Sekarang gunakan hanya untuk loop nilai i akan ditugaskan kembali.
sumber