dict.fromkeys todos apuntan a la misma lista [duplicate]

5 minutos de lectura

Esto me estaba causando un poco de dolor…

Creé un diccionario a partir de una lista.

l = ['a','b','c']
d = dict.fromkeys(l, [0,0]) # initializing dictionary with [0,0] as values

d['a'] is d['b'] # returns True

¿Cómo puedo hacer que cada valor del diccionario sea una lista separada? ¿Es esto posible sin iterar sobre todas las claves y establecerlas como una lista? Me gustaría modificar una lista sin cambiar todas las demás.

Podrías usar una comprensión de dictado:

>>> keys = ['a','b','c']
>>> value = [0, 0]
>>> {key: list(value) for key in keys}
    {'a': [0, 0], 'b': [0, 0], 'c': [0, 0]}

  • list(value) es lo mismo que value[:] ¿aquí?

    – yurisich

    20 de abril de 2014 a las 1:56

  • @Droogans: Sí. Simplemente encuentro fea la notación de rebanada vacía.

    – Licuadora

    20 de abril de 2014 a las 2:51

  • value[:] no es que feo (a menos que compartas el sentido estético de Alex Martelli :)), y es menos tipeo. En versiones recientes de Python ahora hay un list.copy método. En términos de rendimiento, el corte es más rápido para listas pequeñas (hasta 50 o 60 elementos), pero para listas más grandes. list(value) es en realidad un poco más rápido. value.copy() parece tener un rendimiento similar a list(value). Las 3 técnicas se ralentizan drásticamente para listas grandes: en mi vieja máquina de 32 bits que ocurre alrededor de 32k, YMMV dependiendo del tamaño de palabra de su CPU y los tamaños de caché.

    – PM 2 Ring

    14 de julio de 2018 a las 8:25

dictfromkeys todos apuntan a la misma lista duplicate
shawn mehan

Esta respuesta está aquí para explicar este comportamiento a cualquier persona desconcertada por los resultados que obtienen al intentar instanciar un dict con fromkeys() con un valor predeterminado mutable en ese dict.

Considerar:

#Python 3.4.3 (default, Nov 17 2016, 01:08:31) 

# start by validating that different variables pointing to an
# empty mutable are indeed different references.
>>> l1 = []
>>> l2 = []
>>> id(l1)
140150323815176
>>> id(l2)
140150324024968

así que cualquier cambio en l1 no afectará l2 y viceversa. esto sería cierto para cualquier mutable hasta ahora, incluido un dict.

# create a new dict from an iterable of keys
>>> dict1 = dict.fromkeys(['a', 'b', 'c'], [])
>>> dict1
{'c': [], 'b': [], 'a': []}

esta puede ser una función útil. aquí estamos asignando a cada tecla un valor predeterminado que también resulta ser una lista vacía.

# the dict has its own id.
>>> id(dict1)
140150327601160

# but look at the ids of the values.
>>> id(dict1['a'])
140150323816328
>>> id(dict1['b'])
140150323816328
>>> id(dict1['c'])
140150323816328

¡De hecho, todos están usando la misma referencia! ¡Un cambio en uno es un cambio en todos, ya que de hecho son el mismo objeto!

>>> dict1['a'].append('apples')
>>> dict1
{'c': ['apples'], 'b': ['apples'], 'a': ['apples']}
>>> id(dict1['a'])
>>> 140150323816328
>>> id(dict1['b'])
140150323816328
>>> id(dict1['c'])
140150323816328

para muchos, ¡esto no era lo que se pretendía!

Ahora intentemos hacer una copia explícita de la lista que se usa como valor predeterminado.

>>> empty_list = []
>>> id(empty_list)
140150324169864

y ahora crea un dict con una copia de empty_list.

>>> dict2 = dict.fromkeys(['a', 'b', 'c'], empty_list[:])
>>> id(dict2)
140150323831432
>>> id(dict2['a'])
140150327184328
>>> id(dict2['b'])
140150327184328
>>> id(dict2['c'])
140150327184328
>>> dict2['a'].append('apples')
>>> dict2
{'c': ['apples'], 'b': ['apples'], 'a': ['apples']}

¡Todavía no hay alegría! Escuché a alguien gritar, ¡es porque usé una lista vacía!

>>> not_empty_list = [0]
>>> dict3 = dict.fromkeys(['a', 'b', 'c'], not_empty_list[:])
>>> dict3
{'c': [0], 'b': [0], 'a': [0]}
>>> dict3['a'].append('apples')
>>> dict3
{'c': [0, 'apples'], 'b': [0, 'apples'], 'a': [0, 'apples']}

El comportamiento predeterminado de fromkeys() es asignar None al valor

>>> dict4 = dict.fromkeys(['a', 'b', 'c'])
>>> dict4
{'c': None, 'b': None, 'a': None}
>>> id(dict4['a'])
9901984
>>> id(dict4['b'])
9901984
>>> id(dict4['c'])
9901984

De hecho, todos los valores son iguales (¡y los únicos!) None. Ahora, iteremos, en una de las innumerables maneras, a través de la dict y cambiar el valor.

>>> for k, _ in dict4.items():
...    dict4[k] = []

>>> dict4
{'c': [], 'b': [], 'a': []}

Mmm. ¡Se ve igual que antes!

>>> id(dict4['a'])
140150318876488
>>> id(dict4['b'])
140150324122824
>>> id(dict4['c'])
140150294277576
>>> dict4['a'].append('apples')
>>> dict4
>>> {'c': [], 'b': [], 'a': ['apples']}

pero en verdad son diferentes []s, que en este caso era el resultado esperado.

  • Entonces, ¿tenemos que iterar?

    – soñador lucido

    25 de enero de 2018 a las 2:46

  • Pensé que el punto principal era no iterar… ese es el atajo, de lo contrario, ¿por qué necesito esta función en primer lugar?

    –Ricky Levi

    29 de noviembre de 2021 a las 19:59

Puedes usar esto:

l = ['a', 'b', 'c']
d = dict((k, [0, 0]) for k in l)

l = ['a','b','c']
d = dict((i, [0, 0]) for i in l)

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad