第63集:抽象类与接口

学习目标

  • 理解抽象类的概念与作用
  • 掌握 Python 中 abc 模块的使用方法
  • 学会定义抽象方法和抽象属性
  • 理解接口的概念及其在 Python 中的实现方式
  • 能够使用抽象类设计稳定的类层次结构

1. 什么是抽象类

抽象类是一种不能被实例化的类,它的主要目的是为子类提供一个通用的模板,强制子类实现某些方法。
在 Python 中,我们通过 abc(Abstract Base Classes)模块来实现抽象类。

1.1 为什么需要抽象类

  • 定义规范:规定子类必须实现的方法,避免遗漏关键功能
  • 提高可维护性:接口统一,便于多人协作
  • 防止误用:抽象类不能直接创建对象,减少错误使用

2. abc 模块基础

Python 的 abc 模块提供了 ABC 类和 abstractmethod 装饰器来定义抽象类和方法。

2.1 基本语法

from abc import ABC, abstractmethod

class 抽象类名(ABC):
    @abstractmethod
    def 方法名(self):
        pass

2.2 简单示例

from abc import ABC, abstractmethod

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

class Dog(Animal):
    def speak(self):
        return "汪汪!"

class Cat(Animal):
    def speak(self):
        return "喵喵!"

# animal = Animal()  # ❌ TypeError: Can't instantiate abstract class

dog = Dog()
cat = Cat()
print(dog.speak())  # 汪汪!
print(cat.speak())  # 喵喵!

3. 抽象方法

抽象方法是在抽象类中声明但不实现的方法,子类必须重写它,否则子类也是抽象类。

3.1 多抽象方法示例

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)

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    
    def area(self):
        return 3.14159 * self.radius ** 2
    
    def perimeter(self):
        return 2 * 3.14159 * self.radius

# shape = Shape()  # ❌ 无法实例化
rect = Rectangle(3, 4)
circ = Circle(5)
print(f"矩形面积: {rect.area()}, 周长: {rect.perimeter()}")
print(f"圆面积: {circ.area():.2f}, 周长: {circ.perimeter():.2f}")

4. 抽象属性

除了抽象方法,abc 还支持抽象属性,需要使用 @property@abstractmethod 组合。

4.1 抽象属性示例

from abc import ABC, abstractmethod

class Vehicle(ABC):
    @property
    @abstractmethod
    def speed(self):
        pass
    
    @abstractmethod
    def move(self):
        pass

class Car(Vehicle):
    def __init__(self, speed):
        self._speed = speed
    
    @property
    def speed(self):
        return self._speed
    
    def move(self):
        return f"汽车以 {self._speed} km/h 行驶"

class Bicycle(Vehicle):
    def __init__(self, speed):
        self._speed = speed
    
    @property
    def speed(self):
        return self._speed
    
    def move(self):
        return f"自行车以 {self._speed} km/h 骑行"

car = Car(100)
bike = Bicycle(20)
print(car.move())
print(bike.move())

5. 接口的概念与实现

接口是一组方法签名的集合,规定了类应该具备的行为。Python 没有专门的 interface 关键字,但可以用抽象类模拟接口。

5.1 多接口示例

from abc import ABC, abstractmethod

class Flyable(ABC):
    @abstractmethod
    def fly(self):
        pass

class Swimmable(ABC):
    @abstractmethod
    def swim(self):
        pass

class Duck(Flyable, Swimmable):
    def fly(self):
        return "鸭子飞起来了"
    
    def swim(self):
        return "鸭子在水里游泳"

duck = Duck()
print(duck.fly())
print(duck.swim())

6. 实际应用案例:支付系统

假设我们要设计一个支持多种支付方式的系统:

from abc import ABC, abstractmethod

class Payment(ABC):
    @abstractmethod
    def pay(self, amount):
        pass
    
    @abstractmethod
    def refund(self, amount):
        pass

class Alipay(Payment):
    def pay(self, amount):
        return f"支付宝支付 {amount} 元"
    
    def refund(self, amount):
        return f"支付宝退款 {amount} 元"

class WechatPay(Payment):
    def pay(self, amount):
        return f"微信支付 {amount} 元"
    
    def refund(self, amount):
        return f"微信退款 {amount} 元"

def process_payment(payment: Payment, amount):
    print(payment.pay(amount))

alipay = Alipay()
wechat = WechatPay()
process_payment(alipay, 100)
process_payment(wechat, 200)

7. 常见错误与注意事项

  • 抽象类不能直接实例化
  • 子类必须实现所有抽象方法,否则仍是抽象类
  • 抽象属性需用 @property + @abstractmethod
  • 接口可通过多重继承实现
  • 抽象类可以有普通方法(非抽象),子类可直接继承使用

8. 课后练习

  1. 设计一个 Database 抽象类,要求实现 connectqueryclose 三个抽象方法,并用不同的子类实现 MySQL 和 SQLite 的具体逻辑。
  2. 定义一个 Logger 接口(抽象类),包含 log(message) 抽象方法,并实现文件日志和控制台日志两个子类。
  3. 结合属性装饰器,为抽象类添加抽象属性如 version,并在子类中实现。

总结

  • 抽象类:用 ABCabstractmethod 定义,不能实例化,用于约束子类实现关键方法。
  • 接口:在 Python 中用多重抽象类实现,定义行为规范。
  • 抽象类和接口提高了代码的规范性、可扩展性和可维护性,是大型项目设计的重要工具。

下一集我们将进入 魔术方法基础,探索 Python 的特殊方法如何让对象表现得更像内置类型!

« 上一篇 属性装饰器 下一篇 » 魔术方法基础