Nehmen wir an, wir haben ein Python-Wörterbuch d
und iterieren wie folgt darüber:
for k,v in d.iteritems():
del d[f(k)] # remove some item
d[g(k)] = v # add a new item
( f
und g
sind nur einige Black-Box-Transformationen.)
Mit anderen Worten, wir versuchen, Elemente hinzuzufügen / zu entfernen, d
während wir mit darüber iterieren iteritems
.
Ist das gut definiert? Könnten Sie einige Referenzen angeben, um Ihre Antwort zu unterstützen?
(Es ist ziemlich offensichtlich, wie man das behebt, wenn es kaputt ist, also ist dies nicht der Winkel, nach dem ich suche.)
python
dictionary
NPE
quelle
quelle
Antworten:
Auf der Python-Dokumentseite (für Python 2.7 ) wird ausdrücklich darauf hingewiesen
Ähnliches gilt für Python 3 .
Das gleiche gilt für
iter(d)
,d.iterkeys()
undd.itervalues()
, und ich werde so weit gehen , wie zu sagen , dass es funktioniert fürfor k, v in d.items():
(ich kann nicht genau erinnern , was derfor
Fall ist, aber ich würde nicht überrascht sein , wenn die Umsetzung genanntiter(d)
).quelle
d.items()
sollte in Python 2.7 sicher sein (das Spiel ändert sich mit Python 3), da es im Wesentlichen eine Kopie davon erstelltd
, sodass Sie nicht ändern, worüber Sie iterieren.viewitems()
Alex Martelli spricht hier darüber .
Es ist möglicherweise nicht sicher, den Container zu wechseln (z. B. diktieren), während Sie den Container durchlaufen. So
del d[f(k)]
kann nicht sicher sein. Wie Sie wissen, besteht die Problemumgehung darin,d.items()
(um eine unabhängige Kopie des Containers zu durchlaufen) anstelle vond.iteritems()
(die denselben zugrunde liegenden Container verwendet) zu verwenden.Es ist in Ordnung, den Wert an einem vorhandenen Index des Diktats zu ändern , aber das Einfügen von Werten an neuen Indizes (z. B.
d[g(k)]=v
) funktioniert möglicherweise nicht.quelle
Das kannst du zumindest nicht mit
d.iteritems()
. Ich habe es versucht und Python schlägt fehl mitWenn Sie stattdessen verwenden
d.items()
, funktioniert es.In Python 3 gibt
d.items()
es eine Ansicht in das Wörterbuch, wied.iteritems()
in Python 2. Verwenden Sie dazu stattdessen Python 3d.copy().items()
. Auf diese Weise können wir auch eine Kopie des Wörterbuchs durchlaufen, um zu vermeiden, dass die Datenstruktur, über die wir iterieren, geändert wird.quelle
2to3
Zu Ihrerd.items()
Information , die wörtliche Übersetzung (wie z. B. von ) von Py2 in Py3 istlist(d.items())
, obwohl sied.copy().items()
wahrscheinlich von vergleichbarer Effizienz ist.Ich habe ein großes Wörterbuch mit Numpy-Arrays, daher war das von @ murgatroid99 vorgeschlagene dict.copy (). Keys () -Ding nicht durchführbar (obwohl es funktioniert hat). Stattdessen habe ich die keys_view einfach in eine Liste konvertiert und es hat gut funktioniert (in Python 3.4):
Mir ist klar, dass dies nicht wie die obigen Antworten in den philosophischen Bereich von Pythons Innenleben eintaucht, aber es bietet eine praktische Lösung für das angegebene Problem.
quelle
Der folgende Code zeigt, dass dies nicht genau definiert ist:
Das erste Beispiel ruft g (k) auf und löst eine Ausnahme aus (die Größe des Wörterbuchs wurde während der Iteration geändert).
Das zweite Beispiel ruft h (k) auf und löst keine Ausnahme aus, sondern gibt Folgendes aus:
Was beim Betrachten des Codes falsch erscheint - ich hätte so etwas erwartet:
quelle
{11: 'ax', 12: 'bx', 13: 'cx'}
aber der 21,22,23 sollte Ihnen einen Hinweis darauf geben, was tatsächlich passiert ist: Ihre Schleife hat die Punkte 1, 2, 3, 11, 12, 13 durchlaufen, aber den zweiten nicht aufgenommen Runde neuer Elemente, wenn sie vor den Elementen eingefügt wurden, über die Sie bereits iteriert hatten. Wechseln Sieh()
zu Rückkehrx+5
und Sie erhalten ein weiteres x:'axxx'
usw. oder 'x + 3' und Sie erhalten das großartige'axxxxx'
{11: 'ax', 12: 'bx', 13: 'cx'}
wie Sie sagten, also werde ich meinen Beitrag darüber aktualisieren. In beiden Fällen ist dies eindeutig kein genau definiertes Verhalten.Ich habe das gleiche Problem und habe das folgende Verfahren verwendet, um dieses Problem zu lösen.
Python-Liste kann iteriert werden, auch wenn Sie sie während der Iteration ändern. Wenn Sie also dem folgenden Code folgen, werden 1 unendlich gedruckt.
Wenn Sie also list und dict gemeinsam verwenden, können Sie dieses Problem lösen.
quelle
Python 3 sollten Sie nur:
oder verwenden:
Sie sollten das Originalwörterbuch niemals ändern, da dies zu Verwirrung sowie potenziellen Fehlern oder RunTimeErrors führt. Es sei denn, Sie fügen dem Wörterbuch nur neue Schlüsselnamen hinzu.
quelle
Heute hatte ich einen ähnlichen Anwendungsfall, aber anstatt einfach die Schlüssel im Wörterbuch am Anfang der Schleife zu materialisieren, wollte ich Änderungen am Diktat, um die Iteration des Diktats zu beeinflussen, das ein geordnetes Diktat war.
Am Ende habe ich die folgende Routine erstellt, die auch in jaraco.itertools zu finden ist :
Die Dokumentzeichenfolge veranschaulicht die Verwendung. Diese Funktion könnte anstelle der
d.iteritems()
oben genannten verwendet werden, um den gewünschten Effekt zu erzielen.quelle