0

I was reading the book Fluent Python by Luciano Ramalho and I encountered the following line:

Note that the built-in concrete sequence types do not actually subclass the Sequence and MutableSequence abstract base classes (ABCs) depicted

So I looked into ABCs from Python docs and I am having problems understanding their purpose.

For example, isinstance([], abc.Iterable), returns True for lists, so does abc.Sequence and abc.MutableSequence which makes sense. And so does the following, for both isinstance and issubclass methods.

issubclass(str, abc.MutableSequence) --> False
isinstance((), abc.MutableSequence)  --> False

If I do the following:

class A:
    def __iter__(self):
        pass

a = A()
isinstance(a, abc.Iterable) # True
issubclass(A, abc.Iterable) # True

But A does not subclass abc.Iterable in its class definition (and, I am assuming neither does the other classes mentioned before, according to the book). How does the issubclass / isinstance methods and the ABC Interfaces work here? Do these functions simply look for dunder method signatures in the class definition and matches them with the dunder signatures from the mentioned ABC Class?

I don't see any purpose of the ABC classes other than providing a way of verifying whether a class contains some particular dunder methods, so it would be nice to know more about the purpose of this entire process.

Any kind of help would be appreciated. Thanks.

Shiladitya Bose
  • 893
  • 2
  • 13
  • 31
  • It is true that you can write Python classes without using ABC and just rely on duck typing. You can find more discussion about why you might want to use ABC here: https://stackoverflow.com/questions/3570796/why-use-abstract-base-classes-in-python/3571946 – Code-Apprentice Aug 13 '21 at 14:52
  • 1
    Does this answer your question? [Why use Abstract Base Classes in Python?](https://stackoverflow.com/questions/3570796/why-use-abstract-base-classes-in-python) – Code-Apprentice Aug 13 '21 at 14:52
  • While it's true, in the case of `collections.abc.Iterable`, that you could simply check for the existence of `__iter__` along the MRO, I think `isinstance(a, abc.Iterable)` is a nicer way of saying, "I'm about to iterate over this object, let me check if I can do that first". It becomes even more helpful in the world of type hinting. – Axe319 Aug 13 '21 at 15:07

1 Answers1

5

Iterable defines the __subclasshook__ class method to return True if the class has an __iter__ method.

@classmethod
def __subclasshook__(cls, C):
    if cls is Iterable:
        return _check_methods(C, "__iter__")
    return NotImplemented

There are two ways that a can be a subclass of b. Either a can inherit from b (or a subclass of b), or b.__subclasshook__(a) can return True.

As isinstance(a, b) checks if type(a) is a subclass of b, it is also affected by the definition of __subclasshook__.

chepner
  • 497,756
  • 71
  • 530
  • 681