ZetCode

Python 抽象类

最后修改于 2025 年 3 月 25 日

Python 中的抽象类是不能被实例化的类,它们被设计为供其他类继承。它们充当其他类的蓝图,定义了子类必须实现的通用接口。Python 提供了 abc 模块来处理抽象基类 (ABC)。

当你想为一组相关类定义一个通用 API,同时强制要求在子类中实现某些方法时,抽象类尤其有用。它们通过明确定义子类应该实现的方法,帮助创建更易于维护和可预测的代码。@abstractmethod 装饰器标记了必须在具体子类中被重写的方法。

创建基本抽象类

此示例演示了如何在 Python 中创建和使用简单的抽象类。

basic_abc.py
from abc import ABC, abstractmethod

class Shape(ABC):

    @abstractmethod
    def area(self):
        pass

    @abstractmethod
    def perimeter(self):
        pass

class Rectangle(Shape):

    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height

    def perimeter(self):
        return 2 * (self.width + self.height)

rect = Rectangle(5, 10)
print(rect.area())      # Output: 50
print(rect.perimeter()) # Output: 30

# shape = Shape()  # Raises TypeError

Shape 类是一个抽象基类,它定义了两个抽象方法:areaperimeter。像 Rectangle 这样的任何具体子类都必须实现这些方法。尝试直接实例化抽象类会引发 TypeError

抽象属性

此示例展示了如何在抽象类中定义抽象属性。

abstract_properties.py
from abc import ABC, abstractmethod

class Person(ABC):

    @property
    @abstractmethod
    def name(self):
        pass

    @abstractmethod
    def speak(self):
        pass

class Employee(Person):

    def __init__(self, first_name, last_name):
        self._name = f"{first_name} {last_name}"

    @property
    def name(self):
        return self._name

    def speak(self):
        return f"Hello, my name is {self.name}"

emp = Employee("John", "Doe")
print(emp.name)    # Output: John Doe
print(emp.speak()) # Output: Hello, my name is John Doe

抽象属性将 @property 装饰器与 @abstractmethod 结合使用,要求具体子类实现特定的属性。在此示例中,Employee 类实现了抽象的 name 属性和抽象的 speak 方法。

带具体方法的抽象类

此示例演示了一个包含抽象方法和具体方法的抽象类。

concrete_methods.py
from abc import ABC, abstractmethod

class Database(ABC):
    @abstractmethod
    def connect(self):
        pass

    @abstractmethod
    def query(self, sql):
        pass

    def execute(self, sql):
        conn = self.connect()
        result = self.query(sql)
        conn.close()
        return result

class MySQLDatabase(Database):
    def connect(self):
        print("Connecting to MySQL database")
        return "mysql_connection"

    def query(self, sql):
        print(f"Executing MySQL query: {sql}")
        return "query_results"

db = MySQLDatabase()
db.execute("SELECT * FROM users")

抽象类可以包含子类必须实现的抽象方法,也可以包含提供共享功能的具体方法。在此示例中,execute 方法在抽象类中已完全实现,但它依赖于子类必须提供的抽象方法 connectquery

注册虚拟子类

此示例展示了如何将类注册为抽象基类的虚拟子类,而无需显式继承。

virtual_subclasses.py
from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def make_sound(self):
        pass

class Dog:
    def make_sound(self):
        return "Woof!"

Animal.register(Dog)  # Register Dog as virtual subclass

dog = Dog()
print(isinstance(dog, Animal))  # Output: True
print(issubclass(Dog, Animal))  # Output: True
print(dog.make_sound())         # Output: Woof!

register 方法允许你声明一个类实现了抽象基类,而无需显式继承它。注册的类必须实现所有抽象方法,但这要到你尝试使用这些方法时才会进行检查。这在处理无法修改的类或使用鸭子类型时很有用。

带类方法的抽象类

此示例演示了在抽象基类中使用抽象类方法。

abstract_classmethods.py
from abc import ABC, abstractmethod

class Serializer(ABC):

    @classmethod
    @abstractmethod
    def serialize(cls, data):
        pass

    @classmethod
    @abstractmethod
    def deserialize(cls, serialized_data):
        pass

class JSONSerializer(Serializer):

    @classmethod
    def serialize(cls, data):
        return f"JSON: {data}"

    @classmethod
    def deserialize(cls, serialized_data):
        return serialized_data.replace("JSON: ", "")

print(JSONSerializer.serialize({"key": "value"}))  # Output: JSON: {'key': 'value'}

抽象类方法使用 @classmethod@abstractmethod 装饰器进行定义。子类必须实现这些类方法。当你想在相关类之间强制执行类级别的 API 时,这种模式很有用,例如此示例中的不同序列化格式。

抽象类的多重继承

此示例展示了如何在多重继承中使用抽象类。

multiple_inheritance.py
from abc import ABC, abstractmethod

class Readable(ABC):

    @abstractmethod
    def read(self):
        pass

class Writable(ABC):

    @abstractmethod
    def write(self, data):
        pass

class ReadWriteFile(Readable, Writable):

    def __init__(self, filename):
        self.filename = filename

    def read(self):
        return f"Reading from {self.filename}"

    def write(self, data):
        return f"Writing '{data}' to {self.filename}"

file = ReadWriteFile("example.txt")
print(file.read())            # Output: Reading from example.txt
print(file.write("Hello"))   # Output: Writing 'Hello' to example.txt

抽象类可以通过多重继承组合起来,创建实现多个接口的类。ReadWriteFile 类继承自 ReadableWritable 抽象类,并实现了它们的所有抽象方法。这种方法允许灵活的接口定义,同时保持严格的实现要求。

抽象类的最佳实践

来源

Python abc 模块文档

在本文中,我们探讨了 Python 抽象类,并通过实际示例展示了它们在面向对象设计中的用法。

作者

我叫 Jan Bodnar,是一名热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。到目前为止,我已撰写了 1400 多篇文章和 8 本电子书。我在教授编程方面拥有十多年的经验。

列出所有 Python 教程