Abstract Base Class#

Overview#

Abstract class (还有 abstract method) 是一种实现抽象类, 并让用户去继承, 然后自己实现特定方法的设计模式. Python 中的 abc 库能让你在尝试实例化一个抽象方法没有被实现的抽象类的情况下报错. 防止用户继承了这个类但是忘记实现了某些方法.

Basic Usage#

You can’t instantiate abstract class with abstract methods.

[3]:
import abc
[4]:
class Animal(abc.ABC):
    @abc.abstractmethod
    def bark(self):
        raise NotImplementedError
[5]:
animal = Animal()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[5], line 1
----> 1 animal = Animal()

TypeError: Can't instantiate abstract class Animal with abstract methods bark
[6]:
class Dog(Animal):
    def bark(self):
        print("woof!")

dog = Dog()
dog.bark()
woof!

Use dataclasses with ABC#

[7]:
import dataclasses

@dataclasses.dataclass
class Car(abc.ABC):
    @abc.abstractmethod
    def start(self):
        raise NotImplementedError

car = Car()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[7], line 9
      5     @abc.abstractmethod
      6     def start(self):
      7         raise NotImplementedError
----> 9 car = Car()

TypeError: Can't instantiate abstract class Car with abstract methods start
[8]:
@dataclasses.dataclass
class Tesla(Car):
    def start(self):
        print("telsa engine start!")

telsa = Tesla()
telsa.start()
telsa engine start!

Subclass from ABC and other Base Class#

Note: subclass from other base class first, then abstract class

[9]:
@dataclasses.dataclass
class Base:
    name: str


@dataclasses.dataclass
class Bird(Base, abc.ABC):
    @abc.abstractmethod
    def fly(self):
        raise NotImplementedError

bird = Bird()
car = Car()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[9], line 12
      8     @abc.abstractmethod
      9     def fly(self):
     10         raise NotImplementedError
---> 12 bird = Bird()
     13 car = Car()

TypeError: Can't instantiate abstract class Bird with abstract methods fly
[10]:
@dataclasses.dataclass
class Owl(Base, abc.ABC):
    def fly(self):
        print(f"{self.name} is flying!")


owl = Owl("Hedwig")
owl.fly()
Hedwig is flying!
[11]:
print(owl)
Owl(name='Hedwig')

Abstract method can have logic#

[12]:
class Person(abc.ABC):
    @abc.abstractmethod
    def say_hello(self):
        print("Hello")


class Student(Person):
    def say_hello(self, name: str):
        super().say_hello()
        print(f"My name is {name}")


student = Student()
student.say_hello("alice")
Hello
My name is alice

Abstract method with other decorator#

[14]:
import dataclasses
from functools import cached_property

@dataclasses.dataclass
class Person(abc.ABC):
    firstname: str
    lastname: str

    @abc.abstractmethod
    @cached_property
    def fullname(self) -> str:
        raise NotImplementedError


@dataclasses.dataclass
class Student(Person):
    @cached_property
    def fullname(self):
        print("calculate fullname ...")
        return f"{self.firstname} {self.lastname}"


student = Student(firstname="john", lastname="doe")
print(student.fullname)
print(student.fullname)
calculate fullname ...
john doe
john doe
[ ]: