Menu
CoddyTech

抽象类和抽象方法

本课属于 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 创建抽象类。子类必须实现所有抽象方法,否则它们也会是抽象类。这样可以确保一致性,并防止出现不完整的实现。

challenge icon

挑战

中等

在这个挑战中,你将实现一个支付处理系统。

你需要在以下文件中完成实现:

  • 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()  # 无法实例化抽象类
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Python 在线编译器