Jak uniknąć błędu "RuntimeError: dictionary changed size during iteration"?

Sprawdziłem wszystkie inne pytania z tym samym błędem, ale nie znalazłem pomocnego rozwiązania =/

Mam słownik list:

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

, w którym niektóre wartości są puste. Na koniec tworzenia tych list chcę usunąć te puste listy przed zwróceniem mojego słownika. Obecnie próbuję to zrobić w następujący sposób:

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

To jednak powoduje błąd runtime. Zdaję sobie sprawę, że nie można dodawać/usuwać elementów w słowniku podczas iteracji przez to...jak można to obejść?

Author: gsamaras, 2012-08-14

5 answers

W Pythonie 2.x wywołanie keys tworzy kopię klucza, który można iterować podczas modyfikowania dict:

for i in d.keys():

Zauważ, że to nie działa w Pythonie 3.x ponieważ keys zwraca iterator zamiast listy.

Innym sposobem jest użycie list, aby wymusić kopię kluczy, które mają być wykonane. Ten działa również w Pythonie 3.x:

for i in list(d):
 254
Author: Mark Byers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-11 19:16:43

Wystarczy użyć rozumienia słownika, aby skopiować odpowiednie elementy do nowego dict

>>> 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]}
 22
Author: Maria Zverina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-13 20:38:00

Wystarczy użyć "copy":

W ten sposób można iterację nad oryginalnymi polami słownika i w locie można zmienić żądany dict(d dict). To praca nad każdą wersją Pythona, więc jest bardziej przejrzysta.

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]}
 17
Author: Alon Elharar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-13 14:37:46

W pierwszej kolejności starałbym się unikać wstawiania pustych list, ale generalnie używałbym:

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

Jeśli przed 2.7:

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

Lub po prostu:

empty_key_vals = list(k for k in k,v in d.iteritems() if v)
for k in empty_key_vals:
    del[k]
 11
Author: Jon Clements,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-13 20:42:10

Dla Pythona 3:

{k:v for k,v in d.items() if v}
 5
Author: ucyo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-16 07:47:20