开发者

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).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜