【Python从入门到精通】第 009 篇:面向对象编程(二):继承、封装与多态
系列说明:本系列共30篇,涵盖Python开发完整学习路径。本文为第009篇,深入讲解面向对象三大特性:继承、封装与多态的实现与应用。
摘要
本文是面向对象编程系列的第二篇,将深入探讨Python中面向对象的三大核心特性:继承、封装与多态。继承允许我们基于现有类创建新类,实现代码复用和层次化设计;封装通过访问控制保护数据完整性,隐藏实现细节;多态则让不同类的对象能够以统一接口进行操作,增强代码的灵活性和可扩展性。文章将从基础概念出发,通过丰富的代码示例,详细讲解单继承与多继承的实现、方法重写、super()函数的使用、私有属性与@property装饰器、鸭子类型与抽象基类等核心知识点。
一、继承基础
1.1 什么是继承
继承(Inheritance)是面向对象编程的核心特性之一,它允许一个类(子类/派生类)基于另一个类(父类/基类)来构建,自动获得父类的属性和方法。
继承的核心价值:
- 代码复用:避免重复编写相同的代码
- 层次化组织:建立清晰的类层次结构
- 扩展性:在保留原有功能的基础上添加新功能
1.2 单继承的实现
Python中使用以下语法实现单继承:
class Animal:
"""动物基类"""
def __init__(self, name: str, age: int) -> None:
self.name = name
self.age = age
def speak(self) -> str:
return f"{self.name} 发出声音"
def introduce(self) -> str:
return f"我是{self.name},今年{self.age}岁"
class Dog(Animal):
"""狗类,继承自Animal"""
def __init__(self, name: str, age: int, breed: str) -> None:
super().__init__(name, age)
self.breed = breed
def speak(self) -> str:
return f"{self.name} 说:汪汪汪!"
def fetch(self) -> str:
return f"{self.name} 正在捡球"
class Cat(Animal):
"""猫类,继承自Animal"""
def speak(self) -> str:
return f"{self.name} 说:喵喵喵~"
def climb(self) -> str:
return f"{self.name} 正在爬树"
# 测试代码
dog = Dog("旺财", 3, "金毛")
cat = Cat("咪咪", 2)
print(dog.introduce()) # 继承自Animal的方法
print(dog.speak()) # Dog重写的方法
print(dog.fetch()) # Dog特有的方法
print()
print(cat.introduce()) # 继承自Animal的方法
print(cat.speak()) # Cat重写的方法
print(cat.climb()) # Cat特有的方法
输出结果:
我是旺财,今年3岁
旺财 说:汪汪汪!
旺财 正在捡球
我是咪咪,今年2岁
咪咪 说:喵喵喵~
咪咪 正在爬树
1.3 多继承的语法
Python支持多继承,即一个类可以同时继承多个父类:
class Flyable:
"""可飞行接口"""
def fly(self) -> str:
return f"{self.name} 在天空中飞翔"
class Swimmable:
"""可游泳接口"""
def swim(self) -> str:
return f"{self.name} 在水中游泳"
class Duck(Animal, Flyable, Swimmable):
"""鸭子类,继承自动物、可飞行、可游泳"""
def speak(self) -> str:
return f"{self.name} 说:嘎嘎嘎!"
duck = Duck("唐老鸭", 5)
print(duck.speak()) # Duck重写的方法
print(duck.fly()) # 继承自Flyable
print(duck.swim()) # 继承自Swimmable
1.4 方法解析顺序(MRO)
当使用多继承时,Python需要确定方法调用的顺序,这就是方法解析顺序(Method Resolution Order, MRO)。
class A:
def method(self):
print("A.method")
class B(A):
def method(self):
print("B.method")
class C(A):
def method(self):
print("C.method")
class D(B, C):
pass
# 查看MRO
print(D.__mro__)
# 输出:(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
d = D()
d.method() # 输出:B.method(按MRO顺序找到的第一个method)
二、子类方法重写
2.1 方法重写基础
方法重写(Override)是指子类重新定义父类中已有的方法。
class Vehicle:
"""交通工具基类"""
def __init__(self, brand: str) -> None:
self.brand = brand
def start(self) -> str:
return f"{self.brand} 车辆启动"
class ElectricCar(Vehicle):
"""电动汽车"""
def __init__(self, brand: str, battery_capacity: float) -> None:
super().__init__(brand)
self.battery_capacity = battery_capacity
def start(self) -> str:
return f"{self.brand} 电动汽车静音启动"
def charge(self) -> str:
return f"{self.brand} 充电完成"
tesla = ElectricCar("特斯拉", 75.0)
print(tesla.start()) # 调用重写后的方法
print(tesla.stop()) # 调用继承自父类的方法
2.2 super() 函数调用父类方法
super()函数用于调用父类(超类)的方法:
class Rectangle:
"""矩形类"""
def __init__(self, width: float, height: float) -> None:
self.width = width
self.height = height
def area(self) -> float:
return self.width * self.height
def describe(self) -> str:
return f"矩形:宽{self.width},高{self.height},面积{self.area()}"
class Square(Rectangle):
"""正方形类"""
def __init__(self, side: float) -> None:
super().__init__(side, side)
def describe(self) -> str:
base_desc = super().describe()
return f"{base_desc}\n这是一个正方形,边长为{self.width}"
square = Square(5)
print(square.describe())
三、封装实现
3.1 私有属性的保护
封装(Encapsulation)是隐藏对象内部实现细节的编程原则。Python通过命名约定来实现访问控制:
class BankAccount:
"""银行账户类"""
def __init__(self, owner: str, initial_balance: float = 0.0) -> None:
self.owner = owner
self._transaction_history = [] # 受保护属性
self.__balance = initial_balance # 私有属性
def deposit(self, amount: float) -> str:
if amount <= 0:
return "存款金额必须大于0"
self.__balance += amount
self._transaction_history.append(f"存款: +{amount}")
return f"成功存入 {amount} 元"
def get_balance(self) -> float:
return self.__balance
account = BankAccount("张三", 1000.0)
print(account.deposit(500.0))
# 尝试直接访问私有属性
# print(account.__balance) # 会报错:AttributeError
print(f"余额通过方法访问:{account.get_balance()}")
3.2 使用@property实现优雅封装
class Circle:
"""圆形类"""
def __init__(self, radius: float) -> None:
self._radius = radius
@property
def radius(self) -> float:
"""半径的Getter"""
return self._radius
@radius.setter
def radius(self, value: float) -> None:
if value < 0:
raise ValueError("半径不能为负数")
self._radius = value
@property
def area(self) -> float:
"""面积(只读属性)"""
import math
return math.pi * self._radius ** 2
circle = Circle(5.0)
print(f"半径:{circle.radius}")
print(f"面积:{circle.area:.2f}")
circle.radius = 10.0
print(f"修改后面积:{circle.area:.2f}")
四、多态应用
4.1 什么是多态
多态(Polymorphism)是指不同类型的对象对同一消息做出不同响应的能力。
class Duck:
def quack(self) -> str:
return "嘎嘎嘎!"
class Person:
def quack(self) -> str:
return "人在模仿鸭子叫:嘎嘎嘎~"
def make_it_quack(obj) -> None:
"""鸭子类型示例"""
print(f"叫声:{obj.quack()}")
duck = Duck()
person = Person()
make_it_quack(duck)
make_it_quack(person)
4.2 抽象基类(ABC)
Python的abc模块提供了定义抽象基类的机制:
from abc import ABC, abstractmethod
from typing import List
class Shape(ABC):
"""形状抽象基类"""
@abstractmethod
def area(self) -> float:
"""计算面积"""
pass
@abstractmethod
def perimeter(self) -> float:
"""计算周长"""
pass
class Rectangle(Shape):
def __init__(self, width: float, height: float) -> None:
self.width = width
self.height = height
def area(self) -> float:
return self.width * self.height
def perimeter(self) -> float:
return 2 * (self.width + self.height)
class Circle(Shape):
def __init__(self, radius: float) -> None:
self.radius = radius
def area(self) -> float:
import math
return math.pi * self.radius ** 2
def perimeter(self) -> float:
import math
return 2 * math.pi * self.radius
def calculate_total_area(shapes: List[Shape]) -> float:
return sum(shape.area() for shape in shapes)
shapes = [Rectangle(5, 3), Circle(4)]
print(f"总面积:{calculate_total_area(shapes):.2f}")
五、组合与继承的选择
5.1 继承的适用场景
继承适用于明确的"是一个"关系:
class Employee:
def __init__(self, name: str, salary: float) -> None:
self.name = name
self.salary = salary
class Manager(Employee):
"""经理是一个员工(is-a关系)"""
def __init__(self, name: str, salary: float, department: str) -> None:
super().__init__(name, salary)
self.department = department
5.2 组合的适用场景
组合适用于**"有一个"关系**:
class Engine:
def __init__(self, horsepower: int) -> None:
self.horsepower = horsepower
class Car:
"""汽车由多个部件组合而成"""
def __init__(self, brand: str, engine: Engine) -> None:
self.brand = brand
self.engine = engine
v8_engine = Engine(400)
sports_car = Car("跑车", v8_engine)
六、综合实战:设计一个动物园系统
from abc import ABC, abstractmethod
from typing import List
class Animal(ABC):
"""动物抽象基类"""
def __init__(self, name: str, age: int, food_per_day: float) -> None:
self.name = name
self.age = age
self.food_per_day = food_per_day
@property
@abstractmethod
def species(self) -> str:
pass
@abstractmethod
def make_sound(self) -> str:
pass
def eat(self, food_amount: float) -> str:
return f"{self.name} 吃了 {food_amount}kg 食物"
class Lion(Animal):
@property
def species(self) -> str:
return "狮子"
def make_sound(self) -> str:
return f"{self.name} 发出吼叫:ROAR!!!"
class Monkey(Animal):
@property
def species(self) -> str:
return "猴子"
def make_sound(self) -> str:
return f"{self.name} 吱吱叫"
class Zoo:
"""动物园"""
def __init__(self, name: str) -> None:
self.name = name
self.animals: List[Animal] = []
def add_animal(self, animal: Animal) -> None:
self.animals.append(animal)
print(f"欢迎 {animal.species} {animal.name} 加入{self.name}!")
def show_animals(self) -> None:
for animal in self.animals:
print(f"- {animal.species} {animal.name},{animal.age}岁")
# 测试
zoo = Zoo("快乐动物园")
zoo.add_animal(Lion("辛巴", 5, 8.0))
zoo.add_animal(Monkey("阿布", 3, 2.5))
zoo.show_animals()
七、常见问题与注意事项
7.1 继承相关注意事项
- 避免过深的继承层次:继承层次太深会增加代码复杂度
- 菱形继承问题:使用MRO机制妥善处理
- 遵循里氏替换原则:子类应该能够替换父类
7.2 封装相关注意事项
- 不要过度使用私有属性
- 合理使用
@property
7.3 多态相关注意事项
- 鸭子类型 vs 抽象基类的选择
- 谨慎使用
isinstance()
八、总结
本文深入讲解了Python面向对象编程的三大核心特性:
- 继承:通过继承实现代码复用,支持单继承和多继承
- 封装:通过访问控制保护数据,
@property实现优雅封装 - 多态:通过鸭子类型和抽象基类实现灵活的多态
遵循"组合优于继承"的设计原则,构建可维护的代码结构。
参考资料
更多推荐


所有评论(0)