Abstract base classes and multiple inheritance

Mypy supports Python abstract base classes (ABCs). Abstract classeshave at least one abstract method or property that must be implementedby any concrete (non-abstract) subclass. You can define abstract baseclasses using the abc.ABCMeta metaclass and the @abc.abstractmethodfunction decorator. Example:

  1. from abc import ABCMeta, abstractmethod
  2.  
  3. class Animal(metaclass=ABCMeta):
  4. @abstractmethod
  5. def eat(self, food: str) -> None: pass
  6.  
  7. @property
  8. @abstractmethod
  9. def can_walk(self) -> bool: pass
  10.  
  11. class Cat(Animal):
  12. def eat(self, food: str) -> None:
  13. ... # Body omitted
  14.  
  15. @property
  16. def can_walk(self) -> bool:
  17. return True
  18.  
  19. x = Animal() # Error: 'Animal' is abstract due to 'eat' and 'can_walk'
  20. y = Cat() # OK

Note

In Python 2.7 you have to use @abc.abstractproperty to definean abstract property.

Note that mypy performs checking for unimplemented abstract methodseven if you omit the ABCMeta metaclass. This can be useful if themetaclass would cause runtime metaclass conflicts.

Since you can’t create instances of ABCs, they are most commonly used intype annotations. For example, this method accepts arbitrary iterablescontaining arbitrary animals (instances of concrete Animalsubclasses):

  1. def feed_all(animals: Iterable[Animal], food: str) -> None:
  2. for animal in animals:
  3. animal.eat(food)

There is one important peculiarity about how ABCs work in Python –whether a particular class is abstract or not is somewhat implicit.In the example below, Derived is treated as an abstract base classsince Derived inherits an abstract f method from Base anddoesn’t explicitly implement it. The definition of Derivedgenerates no errors from mypy, since it’s a valid ABC:

  1. from abc import ABCMeta, abstractmethod
  2.  
  3. class Base(metaclass=ABCMeta):
  4. @abstractmethod
  5. def f(self, x: int) -> None: pass
  6.  
  7. class Derived(Base): # No error -- Derived is implicitly abstract
  8. def g(self) -> None:
  9. ...

Attempting to create an instance of Derived will be rejected,however:

  1. d = Derived() # Error: 'Derived' is abstract

Note

It’s a common error to forget to implement an abstract method.As shown above, the class definition will not generate an errorin this case, but any attempt to construct an instance will beflagged as an error.

A class can inherit any number of classes, both abstract andconcrete. As with normal overrides, a dynamically typed method canoverride or implement a statically typed method defined in any baseclass, including an abstract method defined in an abstract base class.

You can implement an abstract property using either a normalproperty or an instance variable.