Wie kann ich den Fehler „RuntimeError: Größe des Wörterbuchs während der Iteration geändert“ vermeiden?

Lesezeit: 8 Minuten

Benutzeravatar von user1530318
Benutzer1530318

Ich habe ein Wörterbuch mit Listen, in denen einige Werte leer sind:

d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]}

Am Ende der Erstellung dieser Listen möchte ich diese leeren Listen entfernen, bevor ich mein Wörterbuch zurückgebe. Ich habe es so versucht:

for i in d:
    if not d[i]:
        d.pop(i)

aber ich habe eine RuntimeError. Mir ist bewusst, dass Sie Elemente in einem Wörterbuch nicht hinzufügen/entfernen können, während Sie es durchlaufen … was wäre dann ein Weg, dies zu umgehen?


Siehe Ändern eines Python-Diktats während des Iterierens für Zitate, dass dies Probleme verursachen kann und warum.

  • Zusätzlich zu den unten gegebenen Antworten können Sie erwägen, an den Stellen, an denen Sie Elemente aus der Liste entfernen, nach der leeren Liste zu suchen. Sie könnten eine Hilfsfunktion schreiben: def remove_helper(d, k, elem): d[k].remove(elem); if not d[k]: del d[k].

    – Josefville

    7. Oktober 2022 um 17:43 Uhr


Benutzeravatar von Mark Byers
Markus Byers

In Python 3.x und 2.x können Sie use verwenden list um eine Kopie der Schlüssel zu erzwingen:

for i in list(d):

Beim Aufrufen von Python 2.x keys eine Kopie der Schlüssel erstellt, über die Sie iterieren können, während Sie die ändern dict:

for i in d.keys():

Beachten Sie jedoch, dass diese zweite Methode in Python 3.x bei Ihrem Fehler nicht hilft, weil keys gibt ein a zurück Objekt ansehen anstatt die Schlüssel in eine Liste zu kopieren.

  • Ich glaube, Sie meinten „anrufen“. keys macht eine Kopie davon Schlüssel dass Sie iterieren können aka the plural Schlüssel richtig? Wie kann man sonst über einen einzelnen Schlüssel iterieren? Ich bin übrigens nicht pingelig, ich bin wirklich daran interessiert zu wissen, ob das tatsächlich Schlüssel oder Schlüssel sind

    – AjB

    17. Juni 2016 um 10:34 Uhr


  • Oder Tupel statt Liste, da es schneller ist.

    – Brambor

    7. September 2018 um 2:54 Uhr

  • Um das Verhalten von Python 3.x zu verdeutlichen, gibt d.keys() eine zurück wiederholbar (kein Iterator), was bedeutet, dass es sich um eine direkte Ansicht der Schlüssel des Wörterbuchs handelt. Verwenden for i in d.keys() funktioniert tatsächlich in Python 3.x Im Algemeinenaber weil es über eine iterierbare Ansicht der Schlüssel des Wörterbuchs iteriert, wird aufgerufen d.pop() während der Schleife führt zu dem gleichen Fehler, den Sie gefunden haben. for i in list(d) emuliert das etwas ineffiziente Verhalten von Python 2, die Schlüssel vor dem Iterieren in eine Liste zu kopieren, für besondere Umstände wie Ihren.

    – Michael Krebs

    1. November 2018 um 14:08 Uhr


  • In python3.x, list(d.keys()) erzeugt die gleiche Ausgabe wie list(d)anrufen list auf einen dict gibt die Schlüssel zurück. Der keys Anruf (wenn auch nicht so teuer) ist unnötig.

    – Sean Breckenridge

    8. Mai 2020 um 6:27 Uhr


  • @DanielChin: Diese Dokumentation ist für die falsche Version von Python. Sehen docs.python.org/3/library/stdtypes.html#dict.items.

    – Ry-

    9. Juli 2022 um 2:01 Uhr

Benutzeravatar von Alon Elharar
Alon Elharar

Sie müssen nur verwenden copy:

Auf diese Weise iterieren Sie über die ursprünglichen Wörterbuchfelder und können das gewünschte Diktat spontan ändern d. Es funktioniert auf jeder Python-Version, also ist es klarer.

In [1]: d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]}

In [2]: for i in d.copy():
   ...:     if not d[i]:
   ...:         d.pop(i)
   ...:         

In [3]: d
Out[3]: {'a': [1], 'b': [1, 2]}

(Übrigens – Im Allgemeinen, um über die Kopie Ihrer Datenstruktur zu iterieren, anstatt sie zu verwenden .copy für Wörterbücher oder Slicing [:] für Listen können Sie verwenden import copy -> copy.copy (für eine flache Kopie, die äquivalent ist zu copy das wird durch Wörterbücher oder Slicing unterstützt [:] die von Listen unterstützt wird) oder copy.deepcopy auf Ihre Datenstruktur.)

  • for key, value in dic.copy().items():

    – Asem

    26. September 2022 um 19:28 Uhr


Benutzeravatar von Maria Zverina
Maria Zverina

Benutz einfach Wörterbuch Verständnis So kopieren Sie die relevanten Elemente in ein neues Diktat:

>>> d
{'a': [1], 'c': [], 'b': [1, 2], 'd': []}
>>> d = {k: v for k, v in d.items() if v}
>>> d
{'a': [1], 'b': [1, 2]}

Dazu in Python 2:

>>> d
{'a': [1], 'c': [], 'b': [1, 2], 'd': []}
>>> d = {k: v for k, v in d.iteritems() if v}
>>> d
{'a': [1], 'b': [1, 2]}

  • d.iteritems() gab mir einen Fehler. ich benutzte d.items() stattdessen – mit python3

    – wcyn

    12. Dezember 2016 um 9:54 Uhr


  • Dies funktioniert für das in der Frage von OP gestellte Problem. Jeder, der hierher kam, nachdem er diesen RuntimeError in Multithread-Code getroffen hat, sollte sich jedoch bewusst sein, dass die GIL von CPython auch in der Mitte des Listenverständnisses veröffentlicht werden kann und Sie es anders beheben müssen.

    – Yirkha

    21. Juli 2017 um 9:03 Uhr


  • Ist Wörterbuchverständnis dasselbe wie Listenverständnis? Das Wörterbuchverständnis scheint nicht sehr beliebt zu sein (oder in der offiziellen Dokumentation). Es gibt PEP 274aber wurde es umgesetzt?

    – Peter Mortensen

    2. Februar um 16:30 Uhr


Benutzeravatar von singrium
singrium

Das hat bei mir funktioniert:

d = {1: 'a', 2: '', 3: 'b', 4: '', 5: '', 6: 'c'}
for key, value in list(d.items()):
    if value == '':
        del d[key]
print(d)
# {1: 'a', 3: 'b', 6: 'c'}

Durch das Umwandeln der Wörterbuchelemente in die Liste wird eine Liste ihrer Elemente erstellt, sodass Sie darüber iterieren und das vermeiden können RuntimeError.

Ich würde versuchen, das Einfügen leerer Listen von vornherein zu vermeiden, würde aber im Allgemeinen Folgendes verwenden:

d = {k: v for k,v in d.iteritems() if v} # re-bind to non-empty

Wenn vor 2.7:

d = dict( (k, v) for k,v in d.iteritems() if v )

oder nur:

empty_key_vals = list(k for k in k,v in d.iteritems() if v)
for k in empty_key_vals:
    del[k]

  • +1: Die letzte Option ist interessant, da sie nur die Schlüssel der Elemente kopiert, die gelöscht werden müssen. Dies kann zu einer besseren Leistung führen, wenn relativ zur Größe des Diktats nur eine kleine Anzahl von Elementen gelöscht werden muss.

    – Mark Byers

    13. August 2012 um 20:45 Uhr


  • @MarkByers yup – und wenn eine große Anzahl dies tut, ist es eine bessere Option, das Diktat erneut an ein neues zu binden, das gefiltert wird. Es ist immer die Erwartung, wie die Struktur funktionieren soll

    – Jon Clements

    13. August 2012 um 20:50 Uhr

  • Eine Gefahr beim Rebinding besteht darin, dass es die Änderungen nicht sehen würde, wenn irgendwo im Programm ein Objekt einen Verweis auf das alte Diktat enthielt. Wenn Sie sicher sind, dass dies nicht der Fall ist, dann sicher … das ist ein vernünftiger Ansatz, aber es ist wichtig zu verstehen, dass es nicht ganz dasselbe ist, wie das ursprüngliche Diktat zu ändern.

    – Mark Byers

    13. August 2012 um 20:53 Uhr


  • @MarkByers extrem guter Punkt – Sie und ich wissen das (und unzählige andere), aber es ist nicht für alle offensichtlich. Und ich lege Geld auf den Tisch es hat dich auch nicht in den Hintern gebissen 🙂

    – Jon Clements

    13. August 2012 um 21:06 Uhr


  • Der Punkt, um das Einfügen leerer Einträge zu vermeiden, ist sehr gut.

    – Magnus Bodin

    27. Dezember 2019 um 20:13 Uhr

Benutzeravatar von Peter Mortensen
Peter Mortensen

Um “Wörterbuch geänderte Größe während Iterationsfehler” zu vermeiden.

Zum Beispiel: “wenn Sie versuchen, einen Schlüssel zu löschen”,

Verwenden Sie einfach ‘list’ mit ‘.items()’. Hier ist ein einfaches Beispiel:

my_dict = {
    'k1':1,
    'k2':2,
    'k3':3,
    'k4':4
 
    }
    
print(my_dict)

for key, val in list(my_dict.items()):
    if val == 2 or val == 4:
        my_dict.pop(key)

print(my_dict)

Ausgang:

{'k1': 1, 'k2': 2, 'k3': 3, 'k4': 4}

{'k1': 1, 'k3': 3}

Dies ist nur ein Beispiel. Ändern Sie es basierend auf Ihrem Fall/Ihren Anforderungen.

  • +1: Die letzte Option ist interessant, da sie nur die Schlüssel der Elemente kopiert, die gelöscht werden müssen. Dies kann zu einer besseren Leistung führen, wenn relativ zur Größe des Diktats nur eine kleine Anzahl von Elementen gelöscht werden muss.

    – Mark Byers

    13. August 2012 um 20:45 Uhr


  • @MarkByers yup – und wenn eine große Anzahl dies tut, ist es eine bessere Option, das Diktat erneut an ein neues zu binden, das gefiltert wird. Es ist immer die Erwartung, wie die Struktur funktionieren soll

    – Jon Clements

    13. August 2012 um 20:50 Uhr

  • Eine Gefahr beim Rebinding besteht darin, dass es die Änderungen nicht sehen würde, wenn irgendwo im Programm ein Objekt einen Verweis auf das alte Diktat enthielt. Wenn Sie sicher sind, dass dies nicht der Fall ist, dann sicher … das ist ein vernünftiger Ansatz, aber es ist wichtig zu verstehen, dass es nicht ganz dasselbe ist, wie das ursprüngliche Diktat zu ändern.

    – Mark Byers

    13. August 2012 um 20:53 Uhr


  • @MarkByers extrem guter Punkt – Sie und ich wissen das (und unzählige andere), aber es ist nicht für alle offensichtlich. Und ich lege Geld auf den Tisch es hat dich auch nicht in den Hintern gebissen 🙂

    – Jon Clements

    13. August 2012 um 21:06 Uhr


  • Der Punkt, um das Einfügen leerer Einträge zu vermeiden, ist sehr gut.

    – Magnus Bodin

    27. Dezember 2019 um 20:13 Uhr

Ahmads Benutzeravatar
Ahmad

Für Python3:

{k:v for k,v in d.items() if v}

  • Schön und prägnant. Hat bei mir auch in Python 2.7 funktioniert.

    – ron_g

    17. Januar 2019 um 9:46 Uhr

1443410cookie-checkWie kann ich den Fehler „RuntimeError: Größe des Wörterbuchs während der Iteration geändert“ vermeiden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy