1

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?

mingaleg
  • 2,017
  • 16
  • 28

1 Answers1

3

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.

MisterMiyagi
  • 44,374
  • 10
  • 104
  • 119
  • 2
    This however doesn't explain why also `Awaitable` does this. – Bakuriu Jul 09 '16 at 15:18
  • 1
    @Bakuriu I'd speculate it's from copy-pasting, seeing how `Awaitable` is defined right after `Hashable`. The [docs](https://docs.python.org/3.5/library/collections.abc.html#collections.abc.Awaitable) mention that `Awaitable` doesn't always work properly, so the ABC may not be finalized. Strictly speaking, nothing forbids other ABCs to do the checking of `Hashable` anyways. – MisterMiyagi Jul 09 '16 at 15:34