抽象类和抽象方法
本课属于 Coddy Python 学习旅程的“面向对象编程”单元。第 25 课,共 64 课。
抽象类是不能直接实例化的类,其中包含必须由子类实现的抽象方法。
可以把它想成一张表单:抽象类就像一张必填表单,其中有些字段是必填的(抽象方法),有些是选填的(具体方法)。你不能直接提交表单本身,必须先填写所有必填字段。同样,在子类实现所有抽象方法之前,你不能创建抽象类的实例。
导入 abc 模块来创建抽象类:
from abc import ABC, abstractmethod创建一个包含抽象方法的抽象类:
class Shape(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimeter(self):
pass
def describe(self):
return "This is a shape" # 具体方法(已实现)@abstractmethod 装饰器会标记出子类必须实现的方法,也就是表单中的“必填项”。像 describe() 这样的普通方法可以包含实现,并由子类原样继承,也就是“预填项”。
为什么要使用抽象类?它们可以强制执行契约。如果你创建一个 Shape 类,就意味着“每个形状都必须能够计算自己的面积和周长”。这样可以避免忘记实现关键方法而导致的错误。
试着创建抽象类的一个实例:
# 这会导致错误:
# shape = Shape() # TypeError: Can't instantiate abstract class这个错误是有意触发的,就像试图提交一份空表单。Python 是在说:“你还没有填写必填项(面积和周长方法)!”
创建一个实现所有抽象方法的具体子类:
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
def perimeter(self):
return 2 * 3.14 * self.radius现在,我们已经“填入了所有必需的字段”,也就是实现了 area() 和 perimeter()。Circle 类现在是一个完整的具体类,可以实例化。
现在,你可以创建具体类的实例:
circle = Circle(5)
print(circle.area())
print(circle.perimeter())
print(circle.describe()) # 继承的具体方法再创建一个具体子类:
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)
rectangle = Rectangle(4, 6)
print(rectangle.area())
print(rectangle.perimeter())输出:
78.5
31.400000000000002
This is a shape
24
20抽象类定义了子类必须遵循的契约。使用 ABC 和 @abstractmethod 创建抽象类。子类必须实现所有抽象方法,否则它们也会是抽象类。这样可以确保一致性,并防止出现不完整的实现。
挑战
中等在这个挑战中,你将实现一个支付处理系统。
你需要在以下文件中完成实现:
paymentmethod.py:包含验证逻辑的抽象基类creditcard.py:信用卡支付实现paypal.py:PayPal 支付实现
按照每个文件中的 TODO 注释,实现所需功能。这些注释会逐步引导你创建抽象方法、实现具体子类,并建立文件之间正确的导入关系。
driver.py 文件中包含测试用例,用于验证你的实现是否正常工作。测试会处理不同的支付场景,并显示每种支付方式对应的详细信息。
亲手试试
from creditcard import CreditCard
from paypal import PayPal
# 测试这些实现:不要修改这段测试代码
cc = CreditCard("1234567890123456")
pp = PayPal("user@example.com")
# 处理有效的付款
if cc.validate(100):
print(cc.process_payment(100))
print(cc.payment_details())
if pp.validate(200):
print(pp.process_payment(200))
print(pp.payment_details())
# 试试无效的金额
if not pp.validate(0):
print("Invalid payment amount")
# 如果取消注释,这会引发错误:
# pm = PaymentMethod() # 无法实例化抽象类这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Python 在线编译器