When does Python check whether a concrete subclass of an ABC implements the required methods?

  • A+
Category:Languages

While trying to write unittests that check whether a concrete subclass of an Abstract base class really does raise a TypeError upon instantiation if one of the required methods is not implemented, I stumbled upon something which made me wonder when the check if the required methods is defined by the concrete subclass is actually performed.

Until now I would have said: upon instantiation of the object, since this is the time when the Exception is actually raised when running the program.

But look at this snippet:

import abc  class MyABC(abc.ABC):     @abstractmethod     def foo(self): pass  MyConcreteSubclass(MyABC):     pass 

As expected, trying to instantiate MyConcreteSubclass raises a TypeError:

>>> MyConcreteSubclass() --------------------------------------------------------------------------- TypeError                                 Traceback (most recent call last) <ipython-input-39-fbfc0708afa6> in <module>() ----> 1 t = MySubclass()  TypeError: Can't instantiate abstract class MySubclass with abstract methods foo 

But what happens if I declare a valid subclass at first and then afterwards delete this method surprises me:

class MyConcreteSubclass(MyABC):     def foo(self):         print("bar")  MyConcreteSubclass.foo --> <function __main__.MyConcreteSubclass.foo(self)>   >>> t = MyConcreteSubclass() >>> t.foo() bar  >>> del MyConcreteSubclass.foo >>> MyConcreteSubclass.foo <function __main__.MyABC.foo(self)>  >>> t = MyConcreteSubclass() >>> print(t.foo()) None 

This is certainly not what I expected. When inspecting MyConcreteSubclass.foo after deletion, we see that through the method Resolution order the Abstract method of the base class is retrieved, which is the same behaviour as if we haven't implemented foo in the concrete subclass in the first place.

But after instantiation the TypeError is not raised. So I wonder, are the checks whether the required methods are implemented already performed when the body of the concrete subclass is evaluated by the Interpreter? If so, why are the TypeErrors only raised when someone tries to instantiate the subclass?

The Tests shown above were performed using Python 3.6.5.

 


It happens at class creation time. In Python 3.7, it's in C, in compute_abstract_methods in Modules/_abc.c, which is called as part of ABCMeta.__new__.

Incidentally, the docs do mention that

Dynamically adding abstract methods to a class, or attempting to modify the abstraction status of a method or class once it is created, are not supported.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: