Abstract classes in Python

1
The __subclasscheck__ method must be defined at the metaclass level, since the __subclasshook__ method can be defined as a class method since the class has a ABC metaclass (or one of its derivatives). My question is when we create an abstraction implementing ABCMeta as metaclass, we can make use of the @abstractmethod decorator that defines that the method should be overridden in the derived class, but I have seen in many codes to use these methods ( __subclasscheck__ , __subclasshook__ ) to validate either the implementation of the methods that should be overwritten or to change the behavior of the issubclass() method. Could someone tell me a use case where you should implement these methods.

    
asked by anonymous 02.04.2018 / 08:36

1 answer

4

"Providing use cases" for this type of feature is very complicated - these are features placed in the core of the language to allow for advanced class hierarchy manipulation and customization - the kind of things that will need to be done once , for example in an ORM, or close to the base classes of a project with a large hierarchy of well-defined classes and specificities.

Most of the projects - even the big ones, will use frameworks that will already have this type of functionality defined (be it Django, or some other using SQLAlchemy): ie - it's very difficult imagine a use case for these features. A concrete and simple use case is even more difficult.

Basically, __subclasscheck__ itself, along with __instancecheck__ are functionalities of the language itself. It would not be false to say that they were introduced in the language just to allow the ABC (Abstract base Classes) module to be created with the functionalities that it has today.

Basically they allow you to customize a metaclass and say that some other class, or object of a class unrelated to the classes in your hierarchy (that is, the classes defined with your metaclass), are instances of same - even if this was never the intention of who wrote the original class.

So - to give a concrete example: Python uses the ABCMeta to define the classes in collections.ABC - these yes, being able to have enough use in the day to day, allowing the fast and simple implementation of sequences and mappings by the user (even thus, it has more use in an intermediate library than in a final project). But basically, when designing collections.abc.MutableSequence it would be interesting that if someone asked if a list of Python is a MutableSequence the answer was True: that is, a list does have the interface of a MutableSequence. And this is why these mechanisms are used in the standard Python library: to say that the native Python data types - set, frozenset, list, tuple, string, dict are "subclasses" of the corresponding abstract classes:

In [39]: issubclass(dict, collections.abc.MutableMapping)
Out[39]: True

The same mechanism is used in the typing class of stdlib, which is there to provide type-hinting mechanisms for modern code:

In [41]: issubclass(list, typing.MutableSequence)
Out[41]: True

(The MutableSequence of the typing module however exists to indicate that at that point any type that has the interface of a "Changeable Sequence" will be accepted - whereas collections.abc.MutableSequence on the other hand exists to be a base class for deployments by the user of MutableSequences by typing as few code as possible.)

Already - unlike __subclasscheck__ , which goes in the metaclass and is a language feature, __subclasshook__ is defined only by the abc module and its metaclass ABCMeta - basically the __subclasscheck__ of abc.ABCMeta makes the call to __subclashook__ . That is, the __subclasshook__ mechanism itself is an example of what can be done with __subclasscheck__ : to allow the class itself to have a method to tell if another class is a subclass of itself (without having to write different code in metaclass for each class you want to test this kind of thing for)

In short:

In 98% of cases you will not need any of these features. In case you are defining a class hierarchy that makes use of abstract classes, you can, in the base classes of your hierarchy, use __subclashook__ to say what the answer will be for built-in Python calls issubclass and isinstance for objects (and classes) outside of their hierarchy. (or crossing branches of its hierarchy). These are the remaining "2%".

In the default library this mechanism is used to say that native types like dict, list, etc ... are subclasses of "MutableMapping", "MutableSequence" ... as appropriate.

    
02.04.2018 / 15:47