Corregir Python error = Dictionary Changed Size During Iteration

Isaac Tony 30 enero 2023
  1. Creación de una copia superficial del diccionario
  2. Transmitir elementos del diccionario a una lista
  3. Agregar claves a una lista vacía
Corregir Python error = Dictionary Changed Size During Iteration

Este error de tiempo de ejecución ocurre cuando eliminamos, modificamos o agregamos nuevas entradas en un objeto de diccionario durante la iteración. Este error se produce cuando se itera a través de un diccionario pero prácticamente todos los objetos iterables independientemente del lenguaje de programación utilizado.

El siguiente fragmento de código ilustra cómo se produce este error al recorrer un diccionario y realizar cambios simultáneamente.

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

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

En el bloque de código anterior, agregamos un nuevo elemento al diccionario original mientras iteramos. Esto devolverá un error de tiempo de ejecución, que nos informa que el tamaño del diccionario cambió durante la iteración, lo que implica que no podemos modificar el diccionario mientras se itera simultáneamente.

Código de muestra:

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

Al realizar cualquier iteración en un objeto, tanto la eliminación como la adición o la modificación se consideran una alteración y no se pueden realizar durante la iteración. El siguiente ejemplo de código demuestra que este error también persistirá si modificamos el diccionario mientras iteramos. Por lo tanto, seguiremos obteniendo el mismo error si eliminamos un elemento existente de un diccionario mientras iteramos.

Código de muestra:

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

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

Producción :

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

En Python 3, iterar sobre un objeto cambiante se considera un mal estilo de escritura de código e inseguro. Generalmente, en Programación, no podemos mutar un objeto mientras iteramos sobre él simultáneamente; esta regla se extiende a iterables como listas e incluso matrices.

Sin embargo, si una función muta un objeto, debemos asegurarnos de que la función solo muta una copia del objeto original, dejando el objeto original intacto. Este es uno de los enfoques más utilizados para realizar alteraciones en objetos mientras se itera a través de ellos simultáneamente.

Esta es una buena práctica y la mejor manera de evitar casos de creación de un bucle infinito que eventualmente puede llevar al agotamiento de la memoria. Se pueden usar varias soluciones para manejar este error, y discutiremos cada una aquí.

Creación de una copia superficial del diccionario

Python nos proporciona el módulo copy() que nos permite crear una copia de un objeto sin vinculación al objeto original. Esto nos permite modificar libremente la copia del objeto, dejando intacto el objeto original.

Tenga en cuenta que no se puede realizar lo mismo utilizando el operador de asignación en Python. El uso del operador de asignación no crea una copia del objeto original, sino más bien una variable que se refiere al objeto original.

Por lo tanto, cualquier modificación realizada en el nuevo objeto también afectará al objeto original. Los nuevos desarrolladores a menudo hacen un mal uso de este operador.

Código de muestra:

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)

Producción :

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

En el código de muestra proporcionado, hemos utilizado la función copy del módulo de copia para crear una copia de diccionario que podemos iterar libremente sin afectar el diccionario original. Hacer cambios en una copia de diccionario nos permite iterar sobre el diccionario sin encontrar un error.

Alternativamente, podemos usar el operador ** que a menudo se conoce como los dos operadores de asterisco para reescribir el código anterior, como se muestra a continuación.

Código de muestra:

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)

El operador ** puede tomar pares clave-valor de un diccionario y volcarlos en otro diccionario.

Aunque el operador se usa ampliamente para pasar argumentos de palabras clave en Python, hemos usado el operador para descomprimir el diccionario y obtener los pares clave-valor en el código anterior. Luego creamos una copia del diccionario y volcamos los valores descomprimidos en este nuevo diccionario.

Producción :

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

Eliminar un par clave-valor de un diccionario tampoco es una excepción al realizar una iteración y, por lo tanto, debe seguir un enfoque similar. Por lo tanto, utilizando el mismo procedimiento, eliminaremos la clave denominada model y su valor Model S Plaid como se muestra a continuación.

Código de muestra:

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)

Producción :

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

Otra solución sería crear una copia de las claves sobre la que luego podamos iterar mientras modificamos el diccionario. Sin embargo, esto solo puede funcionar en Python 2 y no en Python 3 porque cuando se hace en Python 3, las claves no devuelven el iterable.

Código de muestra:

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)

Salida de muestra:

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

Transmitir elementos del diccionario a una lista

Dado que no podemos iterar sobre el diccionario mientras hacemos cambios, podemos crear una lista de conversión e iterar sobre la lista mientras hacemos cambios en el diccionario. La iteración sobre la lista de conversión en lugar del diccionario original no devuelve un error de tiempo de ejecución.

Código de muestra:

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

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

print(cars)

Producción :

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

Agregar claves a una lista vacía

Para evitar cambiar el diccionario mientras iteramos, podemos crear una lista vacía que contenga las claves del diccionario mientras realizamos la iteración. Usando esta lista vacía, podemos agregar todas las claves que queremos eliminar o cambiar y luego usar la función pop() para eliminar las claves o la función add para agregar nuevos pares clave-valor.

Esto se puede ejecutar como se muestra en el código siguiente.

Código de muestra:

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)

Producción :

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

Como se muestra a continuación, podemos agregar un nuevo par clave-valor al diccionario usando el mismo procedimiento mientras iteramos usando el bucle for.

Código de muestra:

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)

Producción :

{'brand': 'Tesla', 'model': 'Model S Plaid', 'year': 2021, 'color': 'black'}
Autor: 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

Artículo relacionado - Python Dictionary