I'm trying to understand collections.abc
source code.
Let's take a look on Hashable
class' __subclasshook__
implementation:
@classmethod
def __subclasshook__(cls, C):
if cls is Hashable:
for B in C.__mro__:
if "__hash__" in B.__dict__:
if B.__dict__["__hash__"]:
return True
break
return NotImplemented
Here we first of all check that there is property hash
and than check that it has non-false value. This logic is also presented in Awaitable
class.
And AsyncIterable
class' __subclasshook__
:
@classmethod
def __subclasshook__(cls, C):
if cls is AsyncIterable:
if any("__aiter__" in B.__dict__ for B in C.__mro__):
return True
return NotImplemented
Here we just check that there is __aiter___
property, and this logic is presented in any other classes from this package.
Is there any reason for this logic difference?
The __hash__
protocol explicitly allows flagging a class as unhashable by setting __hash__ = None
.
If a class [...] wishes to suppress hash support, it should include
__hash__ = None
in the class definition.
The reason is that a == b
always requires hash(a) == hash(b)
. Otherwise, dict
, set
and similar data structures break. If a child class changes __eq__
explicitly or otherwise, this may no longer hold true. Thus, __hash__
can be flagged as not applicable.