Search code examples
pythonpython-3.xabc

Inconsistent implementation of collections.abc


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?


Solution

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