在 Python 中,抽象类(Abstract Base Class, ABC)是一种不能被直接实例化的类,它主要用于定义一套子类必须遵守的接口规范。抽象类通过强制子类实现特定的方法,来保证代码的一致性和可维护性。
比如我们需要定义一个图形类,要求所有的子类(三角形、圆形、矩形等等)都必须实现计算面积和周长的方法。我们可以使用抽象类来实现这一点。
使用抽象类有以下几个好处:
- 强制子类实现特定方法:确保所有子类都遵循相同的接口规范,提高代码的一致性。
- 提高代码的可维护性:通过定义抽象类,可以更容易地管理和维护代码。
- 支持多态性:抽象类允许我们使用多态性来处理不同类型的对象,只要它们实现了相同的接口。
创建抽象类
要创建一个抽象类,需要导入 abc 模块,并使用 ABC 作为基类,同时使用 @abstractmethod 装饰器来标记抽象方法。下面是一个示例:
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self) -> float:
pass
@abstractmethod
def perimeter(self) -> float:
pass
在上面的代码中,Shape 类是一个抽象类,定义了两个抽象方法 area 和 perimeter。任何继承自 Shape 的子类都必须实现这两个方法,否则会抛出错误。
下面是如何实现抽象类的示例:
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self) -> float:
return 3.14 * self.radius ** 2
def perimeter(self) -> float:
return 2 * 3.14 * self.radius
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self) -> float:
return self.width * self.height
# 创建 Circle 和 Rectangle 对象
circle = Circle(5)
print("Circle Area:", circle.area()) # 输出: Circle Area: 78.5
print("Circle Perimeter:", circle.perimeter()) # 输出: Circle Perimeter: 31.400000000000002
# 尝试实例化 Shape 类会引发错误
try:
shape = Shape()
except TypeError as e:
print("Error:", e) # 输出: Error: Can't instantiate abstract class Shape without an implementation for abstract methods 'area', 'perimeter'
# Rectangle 类未实现 perimeter 方法,尝试实例化 Rectangle 类会引发错误
try:
rectangle = Rectangle(4, 6)
except TypeError as e:
print("Error:", e) # 输出: Error: Can't instantiate abstract class Rectangle with an implementation for abstract method 'perimeter'
上面的代码展示了如何创建一个抽象类 Shape,以及如何实现它的子类 Circle 和 Rectangle。注意,Rectangle 类没有实现 perimeter 方法,因此尝试实例化它会引发错误。
创建抽象实例属性
抽象类不仅可以包含抽象方法,还可以包含抽象实例属性。使用 @property 装饰器结合 @abstractmethod 来定义抽象属性。
下面示例展示如何创建一个只读的抽象实例属性:
from abc import ABC, abstractmethod
class Person(ABC):
@property
@abstractmethod
def age(self) -> int:
pass
@property
@abstractmethod
def name(self) -> str:
pass
@property
@abstractmethod
def gender(self) -> str:
pass
class Male(Person):
def __init__(self, age: int, name: str):
self._age = age
self._name = name
@property
def age(self) -> int:
return self._age
@property
def name(self) -> str:
return self._name
@property
def gender(self) -> str:
return "Male"
class Female(Person):
def __init__(self, age: int, name: str):
self._age = age
self._name = name
@property
def age(self) -> int:
return self._age
@property
def name(self) -> str:
return self._name
# 获取实例属性
car = Male(age=30, name="John")
print(car.age) # 输出: 30
print(car.name) # 输出: John
print(car.gender) # 输出: Male
# Female 类未实现 gender 属性,尝试实例化 Female 类会引发错误
try:
female = Female(age=25, name="Jane")
except TypeError as e:
print("Error:", e) # 输出: Error: Can't instantiate abstract class Female without an implementation for abstract method 'gender'
# 尝试修改只读的抽象类属性会引发 AttributeError
try:
car.age = 5
except AttributeError as e:
print("Error:", e) # 输出: Error: property 'age' of 'Male' object has no setter
上面的代码展示了如何创建一个只读的抽象实例属性 age、name 和 gender。任何继承自 Person 的子类都必须实现这些属性,否则会抛出错误。
下面示例展示如何创建一个可读写的抽象实例属性:
from abc import ABC, abstractmethod
class Person(ABC):
@property
@abstractmethod
def age(self) -> int:
pass
# 实例属性的 setter 方法,用于设置属性值
@age.setter
@abstractmethod
def age(self) -> int:
pass
@property
@abstractmethod
def name(self) -> str:
pass
@property
@abstractmethod
def gender(self) -> str:
pass
class Male(Person):
def __init__(self, age: int, name: str):
self._age = age
self._name = name
@property
def age(self) -> int:
return self._age
@age.setter
def age(self, value: int):
self._age = value
@property
def name(self) -> str:
return self._name
@property
def gender(self) -> str:
return "Male"
# 获取实例属性
car = Male(age=30, name="John")
print(car.age) # 输出: 30
print(car.name) # 输出: John
print(car.gender) # 输出: Male
# 设置实例属性
car.age = 5
print(car.age) # 输出: 5
实例属性设置了 setter 方法后,就可以对属性进行修改了。
THEEND
© 转载需要保留原始链接,未经明确许可,禁止商业使用。CC BY-NC-ND 4.0