It’s nothing special. As you can see if you examine the unbound __hash__
method of the function type:
>>> def f(): pass
...
>>> type(f).__hash__
<slot wrapper '__hash__' of 'object' objects>
the of 'object' objects
part means it just inherits the default identity-based __hash__
from object
. Function ==
and hash
work by identity. The difference between id
and hash
is normal for any type that inherits object.__hash__
:
>>> x = object()
>>> id(x)
40145072L
>>> hash(x)
2509067
You might think __hash__
is only supposed to be defined for immutable objects, and you’d be almost right, but that’s missing a key detail. __hash__
should only be defined for objects where everything involved in ==
comparisons is immutable. For objects whose ==
is based on identity, it’s completely standard to base hash
on identity as well, since even if the objects are mutable, they can’t possibly be mutable in a way that would change their identity. Files, modules, and other mutable objects with identity-based ==
all behave this way.