[Tutor] Behavior of dictionary in mapping keys that evaluate equal

Peter Otten __peter__ at web.de
Thu May 12 02:46:40 EDT 2016


Steven D'Aprano wrote:

> On Wed, May 11, 2016 at 02:00:47PM +0100, khalil zakaria Zemmoura wrote:
>> Hi,
>> 
>> Suppose we have a dict
>> Dic = { True: 'yes', 1: 'No'}
>> 
>> According to the Python 3 documentation, the keys must have a unique
>> value so True is converted to integer because of the type coercion
>> (boolean are subtype of integer) so boolean are winded to integer to be
>> compared.
> 
> No, not quite. Keys aren't converted to anything. The above is
> equivalent to:
> 
> Dic = {}
> Dic[True] = 'yes'
> Dic[1] = 'no'
> 
> That part is straight-forward. But remember that True == 1:
> 
> py> True == 1
> True
> 
> and they have the same hash:
> 
> py> hash(True), hash(1)
> (1, 1)
> 
> so as far as Python is concerned, they are the same key. The same
> applies to the float 1.0:
> 
> py> d = {True: 'yes'}
> py> d[1]
> 'yes'
> py> d[1.0]
> 'yes'
> 
> 
> One last fact to remember: if the key is already found in the dict, it
> isn't replaced. So:
> 
> py> d = {1: 'no'}
> py> d[True] = 'yes'
> py> d
> {1: 'yes'}
> 
> 
> Does this now explain why
> 
> {True: 'yes', 1: 'no'}
> 
> returns {True: 'no'}?

As Steven says, there is no conversion. The mechanism is completely general: 
The first of a sequence of equal keys wins. 

Here is an example with a custom class:

>>> class Key:
...     def __eq__(self, other):
...         return other == 1
...     def __hash__(self):
...         return 1
...     def __repr__(self):
...         return "<my custom key>"
... 
>>> int(Key())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: int() argument must be a string, a bytes-like object or a number, 
not 'Key'

Even though there is no way to convert a Key to int the dict literals behave 
as with bool and int:

>>> d = {1: "a", Key(): "b"}
>>> d
{1: 'b'}
>>> d = {Key(): "a", 1: "b"}
>>> d
{<my custom key>: 'b'}





More information about the Tutor mailing list