Python - question about hashes and `None`
Why does None
hash to -1042159082
(which I found to be equal to number of bytes in a Gigabyte negated)?
I realize this doesn't really effect my code, but I'm curious.
Hashes are used for dictionary key look-ups, so I decided to experiment:
>>> D = {-1042159082: 'Hello', None: 'Hi'}
>>> D[None]
'Hi'
>>> D[-1042159082]
'Hello'
>>>
开发者_StackOverflow中文版
I understand this as Python seeing two identical hashes and then checking type to see what's what. Is that right?
>>> {False: 'Hello', 0: 'Hi'}
{False: 'Hi'}
>>> {0: 'Hi', False: 'Hello'}
{0: 'Hello'}
This is just weird. What's more is that the first key is kept and the second value is kept.
Is this sorcery, or could somebody help me understand?
About 2 values which may produce the same output when passed to the built-in hash()
function (None
and -1042159082
in the question asked):
This is called a collision (see this page on Wikipedia for more information about collisions).
The hashing algorithm which Python uses has a special way to figure out which value the person really wants when there is a collision (see this page in the source code of CPython (the main Python interpreter), starting at line 51, for information on collisions for dicts, at the time of writing this answer; this file also has notes on how dicts are implemented).
About what happens with 0
and False
(and more useful info), see other answers to the current question.
You can not and should not depend on a particular hash value for a Python object. It's implementation- and machine-dependent. On my machine:
>>> hash(None)
268532216
As far as populating dict
objects goes (there is no hash
object in Python), perhaps the following will help:
>>> False == 0
True
>>> {0: 'Hello', 0: 'Hi'}
{0: 'Hi'}
>>> {0: 'Hi', 0: 'Hello'}
{0: 'Hello'}
>>> {False: 'Hello', False: 'Hi'}
{False: 'Hi'}
>>> {False: 'Hi', False: 'Hello'}
{False: 'Hello'}
When using the dict
constructor, you are supplying two key=value
pairs but both of them have the same key (i.e. hashable value) so, since key values in a dict must be unique, the last value is the one that is saved. In other words, each of the constructors above is creating a one-item dict:
>>> print {False: 'Hello', 0: 'Hi'}
{False: 'Hi'}
See here for more info.
No, even if two objects happen to have the same hash, they still won't cause a key collision. Python detects this and works around it (though please don't ask me how).
But False
is the same as 0
and True
is the same as 1
, so when you're using both in a dict construction, you're updating the value when adding another item with the same key.
How do you figure None hashes to that value?
>>> d = {None:'hi'}
>>> d.get(-1042159082)
>>> d.get(None)
'hi'
>>>
>>> hash(None)
268532214
>>>
I wouldn't rely on the value of hashing None, ever.
As for the dictionary resolution using a literal, I'm assuming that internally, defining a key that 'equals' another, will just do an update instead of a straight add.
>>> class Key(object):
... key = '1'
... def __hash__(self):
... return 1
... def __eq__(self, other):
... return hash(self) == hash(other)
...
>>> class FakeKey(Key):
... key = '2'
...
>>> k = Key()
>>> >>> fk = FakeKey()
>>> d = {k:k,fk:fk}
>>> d
{<__main__.Key object at 0x100489f10>: <__main__.FakeKey object at 0x100489fd0>}
>>> ref = d[k]
>>> ref.key
'2'
>>> d.keys()[0].key
'1'
>>>
Appears I'm right (only appears).
精彩评论