Python 抽象类
最后修改于 2025 年 3 月 25 日
Python 中的抽象类是不能被实例化的类,它们被设计为供其他类继承。它们充当其他类的蓝图,定义了子类必须实现的通用接口。Python 提供了 abc 模块来处理抽象基类 (ABC)。
当你想为一组相关类定义一个通用 API,同时强制要求在子类中实现某些方法时,抽象类尤其有用。它们通过明确定义子类应该实现的方法,帮助创建更易于维护和可预测的代码。@abstractmethod 装饰器标记了必须在具体子类中被重写的方法。
创建基本抽象类
此示例演示了如何在 Python 中创建和使用简单的抽象类。
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 类是一个抽象基类,它定义了两个抽象方法:area 和 perimeter。像 Rectangle 这样的任何具体子类都必须实现这些方法。尝试直接实例化抽象类会引发 TypeError。
抽象属性
此示例展示了如何在抽象类中定义抽象属性。
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 方法。
带具体方法的抽象类
此示例演示了一个包含抽象方法和具体方法的抽象类。
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 方法在抽象类中已完全实现,但它依赖于子类必须提供的抽象方法 connect 和 query。
注册虚拟子类
此示例展示了如何将类注册为抽象基类的虚拟子类,而无需显式继承。
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 方法允许你声明一个类实现了抽象基类,而无需显式继承它。注册的类必须实现所有抽象方法,但这要到你尝试使用这些方法时才会进行检查。这在处理无法修改的类或使用鸭子类型时很有用。
带类方法的抽象类
此示例演示了在抽象基类中使用抽象类方法。
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 时,这种模式很有用,例如此示例中的不同序列化格式。
抽象类的多重继承
此示例展示了如何在多重继承中使用抽象类。
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 类继承自 Readable 和 Writable 抽象类,并实现了它们的所有抽象方法。这种方法允许灵活的接口定义,同时保持严格的实现要求。
抽象类的最佳实践
- 用于 API 定义:抽象类非常适合定义子类必须实现的清晰 API。
- 保持抽象方法最少:只有当方法对于类的目的真正必需时,才将其标记为抽象。
- 记录意图:清晰地记录方法为何是抽象的以及实现应该做什么。
- 偏好组合:考虑组合是否比继承更适合你的用例。
- 测试子类:验证子类是否正确实现了所有抽象方法。
来源
在本文中,我们探讨了 Python 抽象类,并通过实际示例展示了它们在面向对象设计中的用法。
作者
列出所有 Python 教程。