[Python-Dev] Documentation Error for __hash__

Nick Coghlan ncoghlan at gmail.com
Fri Aug 29 18:04:52 CEST 2008

Matt Giuca wrote:
>         It's probably a good idea to implement __hash__ for objects that
>         implement comparisons, but it won't always work and it is certainly
>         not needed, unless you intend to use them as dictionary keys.
>     So you're suggesting that we document something like.
>     Classes that represent mutable values and define equality methods
>     are free to define __hash__ so long as you don't mind them being
>     used incorrectly if treated as dictionary keys...
>     Technically true, but not very helpful in my opinion... :-)
> No, I think he was suggesting we document that if a class overrides
> __eq__, it's a good idea to also implement __hash__, so it can be used
> as a dictionary key.

I strongly advise people interested in this topic to take a closer look
at the functionality that was added to address issue 2235. The "don't
inherit __hash__" behaviour has been backported from 3.0 and broke a
bunch of code, but the naive fix of reverting to the 2.5 behaviour
proceeded to make the 2.6 version of collections.Hashable completely
useless (since pretty much *everything* then claimed to be hashable,
including all of the container types in the standard library).

After thrashing out those problems, the 2.6 behaviour ended up being:
- __hash__ is still inherited by default
- you can block inheritance explicitly by setting "__hash__ = None" in
the class definition or on the class object
- for a class defined in C, you can block __hash__ inheritance by
setting the tp_hash slot to PyObject_HashNotImplemented
- using one of the above approaches will cause hash(obj) to raise a
TypeError, as will calling the tp_hash slot directly
- unlike defining your own __hash__ method, using one of the above
techniques will also mean that isinstance(obj, collections.Hashable)
will also return False
- defining __eq__ and/or __cmp__ without defining __hash__ will lead to
a Py3k Warning being raised on the class definition when run with the -3

The Python 3.0 behaviour is similar to the above, except that the
unconditional inheritance of __hash__ is gone. If you define __eq__ or
__cmp__ without defining __hash__, __hash__ will NOT be inherited from
the parent class - instead, it will be set to None.

The documentation of all of this could definitely use a bit more work -
that's why I reopened 2235 in response to Michael's post.


Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia

More information about the Python-Dev mailing list