Python dictionary does not have all keys or elements assigned

I created the following dictionary

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

and when I type exDict.keys() , well, it gives me a generator. OK, so I force him to the list, and he gives me

 [False, True, 2] 

Why not 1? When I print exDict.items() , it gives me

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

Can anyone guess what is going on here? I'm at a dead end.

+26
python dictionary
May 4 '16 at 3:50
source share
4 answers

This is because True == 1 (and False == 0 , but you did not have 0 as the key). You will have to somehow reorganize your code or data, because the dict considers the keys to be the same if they are "equal" (and not is ).

+28
May 04 '16 at 3:53
source share

What you see is python, forcing 1 to equal True .

You will see that the dictionary you are typing:

 False 1 True a 2 b 

If the value of a is for assignment 1 , but instead, the value for True been reassigned to a .

According to Python 3 Documentation :

The Boolean type is a subtype of the integer type, and Boolean values โ€‹โ€‹behave like the values โ€‹โ€‹0 and 1 , respectively, in almost all contexts, the exception is that when converting to a string, the string "False" or "True" is returned, respectively.

Emphasis on mine.

Note. In python 2.X, True and False can be reassigned, so this behavior cannot be guaranteed.

+12
May 04 '16 at 3:54
source share

Python takes a value of 1 as True . And the Boolean type is a subtype of an integer type

 In [1]: a = {} In [2]: a[True] = 0 In [3]: 1 in a.keys() Out[3]: True 
+5
May 04 '16 at 4:00
source share

If you insert a key-value pair into a python dict check, if the key already exists, and if it exists, it will replace the current value.

This check does something like this:

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

This means that not only the values โ€‹โ€‹should be equal, but also their hash . Unfortunately for you, True and 1 , but also False and 0 will be considered equal keys:

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

and therefore they replace the value ( but not the key):

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

I showed the case of manually adding the key, but the steps taken are the same when using dict literal :

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

or dict -builtin:

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



This can be very important if you write your own classes and want to use them as potential keys inside dictionaries. Depending on your implementation of __eq__ and __hash__ they will and will not replace the values โ€‹โ€‹of the same, but not identical keys:

 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 

Thus, they will not replace existing integer keys:

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

or something that is considered identical:

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

Now they will replace the whole keys:

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

The only thing important is to remember that dictionary keys are kept equal if the objects and their hash are equal.

+2
May 4 '16 at 10:47
source share



All Articles