Correction d'une Python erreur - Dictionary Changed Size During Iteration

Isaac Tony 30 janvier 2023
  1. Création d’une copie superficielle du dictionnaire
  2. Caster des éléments de dictionnaire dans une liste
  3. Ajout de clés à une liste vide
Correction d'une Python erreur - Dictionary Changed Size During Iteration

Cette erreur d’exécution se produit lorsque nous supprimons, modifions ou ajoutons de nouvelles entrées dans un objet de dictionnaire au cours de l’itération. Cette erreur se produit lors de l’itération dans un dictionnaire mais pratiquement tous les objets itérables quel que soit le langage de programmation utilisé.

L’extrait de code ci-dessous illustre comment cette erreur se produit lors de l’itération dans un dictionnaire et en apportant des modifications simultanément.

cars = {"brand": "Tesla", "model": "Model S Plaid", "year": 2021}

for x in cars.keys():
    cars["color"] = "white"
print(x)

Dans le bloc de code ci-dessus, nous ajoutons un nouvel élément au dictionnaire d’origine lors de l’itération. Cela renverra une erreur d’exécution, nous indiquant que la taille du dictionnaire a changé pendant l’itération, ce qui implique que nous ne pouvons pas modifier le dictionnaire tout en itérant simultanément.

Exemple de code :

Traceback (most recent call last):
File "<string>", line 8, in <module>
RuntimeError: dictionary changed size during iteration

Lors de l’exécution d’une itération sur un objet, la suppression, l’ajout ou la modification sont considérés comme une altération et ne peuvent pas être effectués pendant l’itération. L’exemple de code ci-dessous montre que cette erreur persistera également si nous modifions le dictionnaire lors de l’itération. Par conséquent, nous obtiendrons toujours la même erreur si nous supprimons un élément existant d’un dictionnaire lors de l’itération.

Exemple de code :

cars = {"brand": "Tesla", "model": "Model S Plaid", "year": 2021}

for x in cars.keys():
    del cars["model"]
print(cars)

Production :

Traceback (most recent call last):
File "<string>", line 8, in <module>
RuntimeError: dictionary changed size during iteration

Dans Python 3, itérer sur un objet changeant est considéré comme un mauvais style d’écriture de code et dangereux. Généralement, en programmation, nous ne pouvons pas muter un objet tout en l’itérant simultanément ; cette règle s’étend aux itérables tels que les listes et même les tableaux.

Cependant, si une fonction mute un objet, nous devons nous assurer que la fonction ne mute qu’une copie de l’objet d’origine, laissant l’objet d’origine intact. C’est l’une des approches largement utilisées pour apporter des modifications aux objets tout en les itérant simultanément.

C’est une bonne pratique et le meilleur moyen d’éviter les instances de création d’une boucle infinie qui peuvent éventuellement conduire à un épuisement de la mémoire. Plusieurs solutions peuvent être utilisées pour gérer cette erreur, et nous allons discuter de chacune ici.

Création d’une copie superficielle du dictionnaire

Python nous fournit le module copy() qui nous permet de créer une copie d’un objet sans lien avec l’objet original. Cela nous permet de modifier librement la copie de l’objet, en laissant l’objet d’origine intact.

Notez que la même chose ne peut pas être réalisée en utilisant l’opérateur d’affectation en Python. L’utilisation de l’opérateur d’affectation ne crée pas une copie de l’objet d’origine mais plutôt une variable faisant référence à l’objet d’origine.

Par conséquent, toute modification apportée au nouvel objet affectera également l’objet d’origine. Les nouveaux développeurs abusent souvent de cet opérateur.

Exemple de code :

import copy

cars = {
    "brand": "Tesla",
    "model": "Model S Plaid",
    "year": 2021,
}

# creating a shallow copy
cars_copy = copy.copy(cars)

for x in cars_copy.keys():
    cars["color"] = "black"

print(cars)
print(cars_copy)

Production :

{'brand': 'Tesla', 'model': 'Model S Plaid', 'year': 2021, 'color': 'black'}
{'brand': 'Tesla', 'model': 'Model S Plaid', 'year': 2021}

Dans l’exemple de code fourni, nous avons utilisé la fonction copy du module de copie pour créer une copie du dictionnaire que nous pouvons parcourir librement sans affecter le dictionnaire d’origine. Apporter des modifications à une copie de dictionnaire nous permet de parcourir le dictionnaire sans rencontrer d’erreur.

Alternativement, nous pouvons utiliser l’opérateur ** qui est souvent appelé les deux opérateurs astérisques pour réécrire le code ci-dessus, comme indiqué ci-dessous.

Exemple de code :

cars = {"brand": "Tesla", "model": "Model S Plaid", "year": 2021}

# creating a shallow copy
cars_copy = {**cars}


for x in cars_copy.keys():
    cars["color"] = "black"

print(cars)

L’opérateur ** peut prendre des paires clé-valeur d’un dictionnaire et les transférer dans un autre dictionnaire.

Bien que l’opérateur soit largement utilisé pour transmettre des arguments de mot-clé en Python, nous avons utilisé l’opérateur pour décompresser le dictionnaire et obtenir les paires clé-valeur dans le code ci-dessus. Nous créons ensuite une copie du dictionnaire et vidons les valeurs décompressées dans ce nouveau dictionnaire.

Production :

'brand': 'Tesla', 'model': 'Model S Plaid', 'year': 2021, 'color': 'black'}

La suppression d’une paire clé-valeur d’un dictionnaire ne fait pas exception non plus lors de l’exécution d’une itération et doit donc suivre une approche similaire. Par conséquent, en utilisant la même procédure, nous supprimerons la clé nommée model et sa valeur Model S Plaid comme indiqué ci-dessous.

Exemple de code :

import copy

cars = {"brand": "Tesla", "model": "Model S Plaid", "year": 2021, "color": "black"}

cars_copy = copy.copy(cars)

for x in cars_copy.keys():
    if x == "model":
        del cars["model"]

print(cars)

Production :

{'brand': 'Tesla', 'year': 2021, 'color': 'black'}

Une autre solution serait de créer une copie des clés que nous pourrons ensuite parcourir tout en modifiant le dictionnaire. Cependant, cela ne peut fonctionner qu’en Python 2 et non Python 3 car une fois fait en Python 3, les clés ne renvoient pas l’itérable.

Exemple de code :

cars = {"brand": "Tesla", "model": "Model S Plaid", "year": 2021, "color": "black"}

key_copys = list(cars.keys())
print(key_copys)

for key in list(key_copys):
    if cars[key] == "model":
        cars.pop("model")

print(cars)

Exemple de sortie :

['brand', 'model', 'year', 'color']
{'brand': 'Tesla', 'model': 'Model S Plaid', 'year': 2021, 'color': 'black'}

Caster des éléments de dictionnaire dans une liste

Étant donné que nous ne pouvons pas parcourir le dictionnaire tout en apportant des modifications, nous pouvons à la place créer une liste de diffusion et parcourir la liste tout en apportant des modifications au dictionnaire. L’itération sur la liste de diffusion au lieu du dictionnaire d’origine ne renvoie pas d’erreur d’exécution.

Exemple de code :

cars = {"brand": "Tesla", "model": "Model S Plaid", "year": 2021}

for i in list(cars):
    cars["color"] = "black"

print(cars)

Production :

{'brand': 'Tesla', 'model': 'Model S Plaid', 'year': 2021, 'color': 'black'}

Ajout de clés à une liste vide

Pour éviter de changer le dictionnaire pendant l’itération, nous pouvons créer une liste vide contenant les clés du dictionnaire pendant que nous effectuons l’itération. En utilisant cette liste vide, nous pouvons ajouter toutes les clés que nous voulons supprimer ou modifier, puis utiliser la fonction pop() pour supprimer les clés ou la fonction append pour ajouter de nouvelles paires clé-valeur.

Cela peut être exécuté comme indiqué dans le code ci-dessous.

Exemple de code :

cars = {"brand": "Tesla", "model": "Model S Plaid", "year": 2021}

list = []

for i in cars:
    list.append(i)

for x in list:
    if x == "model":
        cars.pop(x)

print(cars)

Production :

{'brand': 'Tesla', 'year': 2021}

Comme indiqué ci-dessous, nous pouvons ajouter une nouvelle paire clé-valeur au dictionnaire en utilisant la même procédure tout en itérant à l’aide de la boucle for.

Exemple de code :

cars = {"brand": "Tesla", "model": "Model S Plaid", "year": 2021}

list = []

for i in cars:
    list.append(i)

for x in list:
    cars["color"] = "black"

print(cars)

Production :

{'brand': 'Tesla', 'model': 'Model S Plaid', 'year': 2021, 'color': 'black'}
Auteur: Isaac Tony
Isaac Tony avatar Isaac Tony avatar

Isaac Tony is a professional software developer and technical writer fascinated by Tech and productivity. He helps large technical organizations communicate their message clearly through writing.

LinkedIn

Article connexe - Python Dictionary