Katakanlah kita memiliki kamus Python d
, dan kita mengulanginya seperti ini:
for k,v in d.iteritems():
del d[f(k)] # remove some item
d[g(k)] = v # add a new item
( f
dan g
hanya beberapa transformasi kotak hitam.)
Dengan kata lain, kami mencoba menambah / menghapus item ke d
saat iterasi menggunakan iteritems
.
Apakah ini didefinisikan dengan baik? Bisakah Anda memberikan beberapa referensi untuk mendukung jawaban Anda?
(Sangat jelas bagaimana cara memperbaikinya jika rusak, jadi ini bukan sudut yang saya cari.)
python
dictionary
NPE
sumber
sumber
Jawaban:
Ini secara eksplisit disebutkan di halaman doc Python (untuk Python 2.7 ) itu
Demikian pula untuk Python 3 .
Hal yang sama berlaku untuk
iter(d)
,d.iterkeys()
dand.itervalues()
, dan saya akan mengatakan bahwa itu berlaku untukfor k, v in d.items():
(saya tidak ingat persis apa yangfor
dilakukannya, tetapi saya tidak akan terkejut jika penerapannya dipanggiliter(d)
).sumber
d.items()
harus aman dengan Python 2.7 (permainan berubah dengan Python 3), karena itu membuat apa yang pada dasarnya adalah salinand
, jadi Anda tidak memodifikasi apa yang Anda iterasi.viewitems()
Alex Martelli mempertimbangkan ini di sini .
Mungkin tidak aman untuk mengganti wadah (mis. Dict) saat memutar ulang wadah. Jadi
del d[f(k)]
mungkin tidak aman. Seperti yang Anda ketahui, solusinya adalah dengan menggunakand.items()
(untuk mengulang salinan independen penampung), bukand.iteritems()
(yang menggunakan penampung pokok yang sama).Tidak masalah untuk mengubah nilai pada indeks yang sudah ada dari dict, tetapi memasukkan nilai pada indeks baru (misalnya
d[g(k)]=v
) mungkin tidak berfungsi.sumber
Anda tidak dapat melakukan itu, setidaknya dengan
d.iteritems()
. Saya mencobanya, dan Python gagalJika Anda malah menggunakan
d.items()
, maka itu berhasil.Di Python 3,
d.items()
adalah tampilan ke dalam kamus, sepertid.iteritems()
di Python 2. Untuk melakukan ini di Python 3, gunakand.copy().items()
. Ini juga akan memungkinkan kita untuk mengulang salinan kamus untuk menghindari modifikasi struktur data yang kita iterasi.sumber
2to3
) dari Py2d.items()
ke Py3 adalahlist(d.items())
, meskipund.copy().items()
mungkin memiliki efisiensi yang sebanding.Saya memiliki kamus besar yang berisi array Numpy, jadi hal dict.copy (). Keys () yang disarankan oleh @ murgatroid99 tidak layak (meskipun berhasil). Sebagai gantinya, saya baru saja mengonversi keys_view ke daftar dan itu berfungsi dengan baik (dengan Python 3.4):
for item in list(dict_d.keys()): temp = dict_d.pop(item) dict_d['some_key'] = 1 # Some value
Saya menyadari ini tidak menyelami dunia filosofis dari cara kerja bagian dalam Python seperti jawaban di atas, tetapi ini memberikan solusi praktis untuk masalah yang dinyatakan.
sumber
Kode berikut menunjukkan bahwa ini tidak didefinisikan dengan baik:
def f(x): return x def g(x): return x+1 def h(x): return x+10 try: d = {1:"a", 2:"b", 3:"c"} for k, v in d.iteritems(): del d[f(k)] d[g(k)] = v+"x" print d except Exception as e: print "Exception:", e try: d = {1:"a", 2:"b", 3:"c"} for k, v in d.iteritems(): del d[f(k)] d[h(k)] = v+"x" print d except Exception as e: print "Exception:", e
Contoh pertama memanggil g (k), dan melempar pengecualian (kamus mengubah ukuran selama iterasi).
Contoh kedua memanggil h (k) dan tidak mengeluarkan pengecualian, tetapi menghasilkan:
{21: 'axx', 22: 'bxx', 23: 'cxx'}
Yang, melihat kodenya, tampaknya salah - saya akan mengharapkan sesuatu seperti:
{11: 'ax', 12: 'bx', 13: 'cx'}
sumber
{11: 'ax', 12: 'bx', 13: 'cx'}
tetapi 21,22,23 harus memberi Anda petunjuk tentang apa yang sebenarnya terjadi: loop Anda melewati item 1, 2, 3, 11, 12, 13 tetapi tidak berhasil mengambil yang kedua putaran item baru saat dimasukkan di depan item yang sudah Anda iterasi. Ubahh()
untuk kembalix+5
dan Anda mendapatkan x:'axxx'
dll. Atau 'x + 3' dan Anda mendapatkan yang luar biasa'axxxxx'
{11: 'ax', 12: 'bx', 13: 'cx'}
seperti yang Anda katakan, jadi saya akan memperbarui posting saya tentang itu. Bagaimanapun, ini jelas bukan perilaku yang didefinisikan dengan baik.Saya mendapat masalah yang sama dan saya menggunakan prosedur berikut untuk menyelesaikan masalah ini.
Daftar Python dapat diulang bahkan jika Anda memodifikasi selama iterasi di atasnya. jadi untuk kode berikut ini akan mencetak 1 tanpa batas.
for i in list: list.append(1) print 1
Jadi dengan menggunakan daftar dan diktekan secara kolaboratif, Anda dapat memecahkan masalah ini.
d_list=[] d_dict = {} for k in d_list: if d_dict[k] is not -1: d_dict[f(k)] = -1 # rather than deleting it mark it with -1 or other value to specify that it will be not considered further(deleted) d_dict[g(k)] = v # add a new item d_list.append(g(k))
sumber
Python 3 Anda hanya harus:
prefix = 'item_' t = {'f1': 'ffw', 'f2': 'fca'} t2 = dict() for k,v in t.items(): t2[k] = prefix + v
atau gunakan:
Anda tidak boleh mengubah kamus asli, ini menyebabkan kebingungan serta potensi bug atau RunTimeErrors. Kecuali Anda hanya menambahkan ke kamus dengan nama kunci baru.
sumber
Hari ini saya memiliki kasus penggunaan yang serupa, tetapi alih-alih hanya mewujudkan kunci di kamus di awal perulangan, saya ingin perubahan pada dict untuk memengaruhi iterasi dari dict, yang merupakan dict berurutan.
Saya akhirnya membangun rutinitas berikut, yang juga dapat ditemukan di jaraco.itertools :
def _mutable_iter(dict): """ Iterate over items in the dict, yielding the first one, but allowing it to be mutated during the process. >>> d = dict(a=1) >>> it = _mutable_iter(d) >>> next(it) ('a', 1) >>> d {} >>> d.update(b=2) >>> list(it) [('b', 2)] """ while dict: prev_key = next(iter(dict)) yield prev_key, dict.pop(prev_key)
Docstring menggambarkan penggunaannya. Fungsi ini dapat digunakan sebagai pengganti di
d.iteritems()
atas untuk mendapatkan efek yang diinginkan.sumber