El diccionario de Python no tiene todas las claves asignadas, o elementos

Creé el siguiente diccionario

exDict = {True: 0, False: 1, 1: 'a', 2: 'b'} 

y cuando exDict.keys() , bueno, me da un generador. Ok, entonces lo coacciono a una lista, y me da

 [False, True, 2] 

¿Por qué no hay 1 allí? Cuando exDict.items() me da

 [(False, 1), (True, 'a'), (2, 'b')] 

¿Alguien tiene una conjetura sobre lo que está pasando aquí? Estoy perplejo.

Esto sucede porque True == 1 (y False == 0 , pero no tenías 0 como clave). Tendrá que refactorizar su código o sus datos de alguna manera, porque un dict considera que las claves son las mismas si son “iguales” (en lugar de is ).

Lo que estás viendo es que Python obliga al 1 a ser igual a la True .

Verás que el diccionario que imprimes es:

 False 1 True a 2 b 

Donde el valor a estaba destinado a ser asignado a 1 , pero en cambio, el valor de True se reasignó a a .

Según la documentación de Python 3 :

El tipo booleano es un subtipo del tipo entero, y los valores booleanos se comportan como los valores 0 y 1 , respectivamente, en casi todos los contextos, con la excepción de que cuando se convierten a una cadena, se devuelven las cadenas “Falso” o “Verdadero” , respectivamente.

Énfasis mío.

Nota: En python 2.X, True y False se pueden reasignar, por lo que no se puede garantizar este comportamiento.

Python toma el 1 como True . Y el tipo booleano es un subtipo del tipo entero

 In [1]: a = {} In [2]: a[True] = 0 In [3]: 1 in a.keys() Out[3]: True 

Si inserta un par clave-valor en un dict Python verifica si la clave ya existe y si existe, reemplazará el valor actual.

Este chequeo hace algo como esto:

 def hash_and_value_equal(key1, key2): return hash(key1) == hash(key2) and key1 == key2 

Así que no solo deben ser iguales los valores, sino también su hash . Desafortunadamente para ti, True y 1 pero también False y 0 se considerarán claves iguales:

 >>> hash_and_value_equal(0, False) True >>> hash_and_value_equal(1, True) True 

y por lo tanto reemplazan el valor ( pero no la clave):

 >>> a = {1: 0} >>> a[True] = 2 >>> a {1: 2} >>> a = {False: 0} >>> a[0] = 2 >>> a {False: 2} 

He mostrado el caso de agregar una clave manualmente, pero los pasos seguidos son los mismos cuando se usa el dict literal :

 >>> a = {False: 0, 0: 2} >>> a {False: 2} 

o el dict -builtin:

 >>> a = dict(((0, 0), (False, 2))) >>> a {0: 2} 

Esto puede ser muy importante si escribe sus propias clases y desea usarlas como posibles claves dentro de los diccionarios. Dependiendo de su implementación de __eq__ y __hash__ estos reemplazarán y no reemplazarán los valores de claves iguales pero no idénticas:

 class IntContainer(object): def __init__(self, value): self.value = value def __eq__(self, other): return self.value == other def __hash__(self): # Just offsetting the hash is enough because it also checks equality return hash(1 + self.value) >>> hash_equal(1, IntContainer(1)) False >>> hash_equal(2, IntContainer(1)) False 

Así que estos no reemplazarán las claves enteras existentes:

 >>> a = {1: 2, IntContainer(1): 3, 2: 4} >>> a {1: 2, <__main__.IntContainer at 0x1ee1258fe80>: 3, 2: 4} 

O algo que se considera como clave idéntica:

 class AnotherIntContainer(IntContainer): def __hash__(self): # Not offsetted hash (collides with integer) return hash(self.value) >>> hash_and_value_equal(1, AnotherIntContainer(1)) True 

Estos ahora reemplazarán las claves enteras:

 >>> a = {1: 2, AnotherIntContainer(1): 5} >>> a {1: 5} 

Lo único realmente importante es tener en cuenta que las claves del diccionario se consideran iguales si los objetos y su hash son iguales.