'Index operator [] on dictionary, in Python
I am trying to understand how index operator [] works in some cases involving dictionaries.
>>> {'a': 1, 'b':2}[1]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 1
However...
>>> {True: 1, False:2, True: 3}[1]
3
What's going on here?
Also, what's with the below?
>>> {True: 1, False:2, True: 3}
{False: 2, True: 3}
Why is {True: 1, False:2, True: 3}" evaluating to "{False: 2, True: 3}"?
When searching for answer, I came across this question, but I couldn't find answers to my questions there.
Thanks.
Solution 1:[1]
{True: 1, False:2, True: 3}1
What's going on here?
This is an extremely specific case, which might be really missguiding. In python "1" is True and "0" is False, thus you can use these integers/floats as boolean keys. However, it is not a regular casting operation, so if you try to use "1.1" as a key, it will not be casted to True, even though bool(1.2)==True. So in general - you have to index with the actual keys. The fact that True is actually 1 "behind the scenes" and False is 0 is a specific exception and you should not write code depending on this behaviour.
d = {True: 'test', False: 'test'}
print d[True] # works, valid use
print d[False] # works, valid use
print d[1] # works due to Python specifics, do not use
print d[0] # works due to Python specifics, do not use
print d[1.0] # works due to Python specifics, do not use
print d[0.0] # works due to Python specifics, do not use
print d[1.1] # raises exception, as it should
print d[''] # raises exception, as it should
This is a consequence of how boolean type is defined in Python
Boolean values are the two constant objects False and True. They are used to represent truth values (although other values can also be considered false or true). In numeric contexts (for example when used as the argument to an arithmetic operator), they behave like the integers 0 and 1, respectively. The built-in function bool() can be used to cast any value to a Boolean, if the value can be interpreted as a truth value (see section Truth Value Testing above).
Thus showing why 1==True and 0==False.
More precisely, Python dictionaries are hash tables, so in order to find a given key one computes its hash (through hash(key)), which points to a given "bucket" and then iteratively checks in that bucker whether key equals to what is in that bucket. And since in Python hash(1) == hash(1.0) == hash(True) and also 1 == 1.0 == True, they will work as the same key. On the other hand hash(1.1) != hash(1.0) so it will not be the same. This shows why it is not casting, it is about equality and hashing.
Why is {True: 1, False:2, True: 3}" evaluating to "{False: 2, True: 3}"?
Its because in a dictionary you can only have one value for each key, you tried to assign two different values to a key "True" and only one got assigned.
Solution 2:[2]
Python dict is a map from key to a value, which maps "hashable" values to arbitrary value objects, you can only have one value per key.
In this case your example
>>> {True: 1, False:2, True: 3}
{False: 2, True: 3}
Is pretty much the same as this
>>> {"a": 1, "b": 2, "a": 3}
{'a': 3, 'b': 2}
Where the only one True, or "a" value is kept.
The access via [] is not an index in a dict, it's referencing via the key. I.e. you could write something like this
>>> my_map = {"a": 1, "b": 2}
>>> my_map["b"]
2
Why 1 works instead of True is because of how booleans have been defined to wkr as the integer values 1 and 0 as @lejlot explains, you should avoid relying on such things whenever possible.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Community |
| Solution 2 |
