Python 继承详解
继承是面向对象编程(OOP)的一个重要特性,允许一个类(子类)从另一个类(父类)继承属性和方法。继承可以提高代码的重用性,增强程序的可扩展性和可维护性。
目录
一、继承的作用
二、继承的语法
1. 单继承
2. 多继承
三、子类扩展
1. 添加新功能
2. 重写父类方法
3. 调用父类方法
四、继承的特殊情况
1. 子类初始化父类
2. 方法解析顺序(MRO)
五、抽象类与接口
1. 抽象类
2. 接口
3. ABC类
4. 使用方法
1. 定义抽象基类
2. 抽象属性
3. 抽象静态方法和类方法
4. 检查子类是否实现抽象方法
5. abc 的高级用法
1. 注册虚拟子类
2. 定义混入类
补充
方法解析顺序(MRO,Method Resolution Order)
一、MRO 的规则
二、查看 MRO
三、MRO 的应用场景
1. 多继承中方法冲突的处理
2. super() 的行为
四、MRO 的规则解析(C3 线性化算法)
步骤
五、特殊情况
1. 菱形继承问题
2. 无法线性化的继承关系
一、继承的作用
-
代码复用
子类继承父类的属性和方法,无需重复编写相同代码。 -
逻辑层次清晰
通过继承关系表达对象间的从属关系,使代码更具结构性。 -
增强扩展性
子类可以在继承父类的基础上扩展新的属性或方法,支持功能扩展。 -
多态性
子类可以重写父类的方法,实现不同的行为。
二、继承的语法
在 Python 中,继承通过类定义时括号中的父类名实现。
1. 单继承
子类继承单个父类:
class Parent:
def greet(self):
print("Hello from Parent")
class Child(Parent):
pass # 子类继承了 Parent 的所有属性和方法
# 使用子类
child = Child()
child.greet() # 输出: Hello from Parent
2. 多继承
子类继承多个父类:
class Parent1:
def greet(self):
print("Hello from Parent1")
class Parent2:
def greet(self):
print("Hello from Parent2")
class Child(Parent1, Parent2):
pass
child = Child()
child.greet() # 输出: Hello from Parent1 (根据继承顺序)
多继承会按照方法解析顺序(MRO)决定调用哪个父类的方法,可用
Class.mro()
或help(Class)
查看。
三、子类扩展
子类可以添加新的属性和方法,或者重写父类的方法。
1. 添加新功能
class Parent:
def greet(self):
print("Hello from Parent")
class Child(Parent):
def say_goodbye(self):
print("Goodbye from Child")
child = Child()
child.greet() # 输出: Hello from Parent
child.say_goodbye() # 输出: Goodbye from Child
2. 重写父类方法
通过在子类中重新定义方法,覆盖父类的同名方法。
class Parent:
def greet(self):
print("Hello from Parent")
class Child(Parent):
def greet(self):
print("Hello from Child") # 重写父类方法
child = Child()
child.greet() # 输出: Hello from Child
3. 调用父类方法
使用 super()
调用父类方法:
class Parent:
def greet(self):
print("Hello from Parent")
class Child(Parent):
def greet(self):
super().greet() # 调用父类方法
print("Hello from Child")
child = Child()
child.greet()
# 输出:
# Hello from Parent
# Hello from Child
四、继承的特殊情况
1. 子类初始化父类
如果父类有 __init__
方法,子类需要显式调用它。
class Parent:
def __init__(self, name):
self.name = name
class Child(Parent):
def __init__(self, name, age):
super().__init__(name) # 调用父类的初始化方法
self.age = age
child = Child("Alice", 10)
print(child.name) # 输出: Alice
print(child.age) # 输出: 10
2. 方法解析顺序(MRO)
多继承时,Python 按 MRO 顺序查找方法。
class A:
def show(self):
print("A")
class B(A):
def show(self):
print("B")
class C(A):
pass
class D(B, C):
pass
print(D.mro())
# 输出: [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
d = D()
d.show() # 输出: B
五、抽象类与接口
通过继承实现抽象类和接口功能。
1. 抽象类
使用 abc
模块定义抽象类,要求子类必须实现特定方法。
from abc import ABC, abstractmethod
class AbstractClass(ABC):
@abstractmethod
def abstract_method(self):
pass
class ConcreteClass(AbstractClass):
def abstract_method(self):
print("Implementation of abstract method")
obj = ConcreteClass()
obj.abstract_method() # 输出: Implementation of abstract method
2. 接口
通过继承实现类似接口的功能,强制子类遵循某些规则:
class Interface:
def method(self):
raise NotImplementedError("Subclasses must implement this method")
class Implementation(Interface):
def method(self):
print("Method implemented")
obj = Implementation()
obj.method() # 输出: Method implemented
3. ABC类
from abc import ABC, abstractmethod, abstractclassmethod, abstractstaticmethod, abstractproperty
-
ABC
类
这是所有抽象基类的基类。 -
@abstractmethod
装饰器
用于定义抽象方法。子类必须实现该方法,否则无法实例化。 -
@abstractclassmethod
、@abstractstaticmethod
和@abstractproperty
用于定义抽象的类方法、静态方法和属性。
抽象基类不能直接实例化,必须由子类实现所有抽象方法后才能实例化。所以上述的AbstractClass类不能直接实例化,必须由ConcreteClass继承后实例化。
4. 使用方法
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)
# 实例化子类
rect = Rectangle(5, 10)
print(rect.area()) # 输出: 50
print(rect.perimeter()) # 输出: 30
# 尝试实例化抽象类会报错
# shape = Shape() # TypeError: Can't instantiate abstract class Shape with abstract methods area, perimeter
2. 抽象属性
使用 @abstractmethod
可以定义抽象属性。
from abc import *
class Shape(ABC):
@property
@abstractmethod
def name(self):
pass
class Circle(Shape):
@property
def name(self):
return "Circle"
circle = Circle()
print(circle.name) # 输出: Circle
3. 抽象静态方法和类方法
可以使用 @abstractstaticmethod
和 @abstractclassmethod
。
from abc import *
class Shape(ABC):
@abstractstaticmethod
def description():
pass
@abstractclassmethod
def create(cls):
pass
class Circle(Shape):
@staticmethod
def description():
return "This is a Circle"
@classmethod
def create(cls):
return cls()
circle = Circle()
print(Circle.description()) # 输出: This is a Circle
circle_instance = Circle.create()
4. 检查子类是否实现抽象方法
如果子类没有实现抽象方法,尝试实例化子类会抛出 TypeError
。
class IncompleteShape(Shape):
pass
# 会报错,因为 IncompleteShape 没有实现 area 和 perimeter
# shape = IncompleteShape() # TypeError: Can't instantiate abstract class IncompleteShape with abstract methods area, perimeter
5. abc
的高级用法
1. 注册虚拟子类
通过 register()
方法,可以将一个类注册为抽象基类的虚拟子类,而无需继承抽象基类。
from abc import ABC
class Shape(ABC):
pass
class Polygon:
def sides(self):
return 4
# 将 Polygon 注册为 Shape 的虚拟子类
Shape.register(Polygon)
polygon = Polygon()
print(isinstance(polygon, Shape)) # 输出: True
注册虚拟子类的行为仅限于 isinstance
和 issubclass
检查,不会强制实现抽象方法。
2. 定义混入类
抽象基类可以作为混入类,提供公共方法供子类继承,同时要求子类实现特定方法。
from abc import ABC, abstractmethod
class JSONSerializable(ABC):
@abstractmethod
def to_json(self):
pass
def save(self, filepath):
with open(filepath, 'w') as f:
f.write(self.to_json())
class User(JSONSerializable):
def __init__(self, name, age):
self.name = name
self.age = age
def to_json(self):
import json
return json.dumps({"name": self.name, "age": self.age})
user = User("Alice", 30)
user.save("user.json")
补充
方法解析顺序(MRO,Method Resolution Order)
方法解析顺序是 Python 中确定在类继承体系中调用方法时的查找顺序的规则。MRO 决定了在多继承场景下,当调用一个方法或属性时,Python 应该从哪个类开始查找,并以什么顺序继续查找。
一、MRO 的规则
-
深度优先、左到右
Python 遵循一种称为 C3 线性化算法 的规则,该规则优先考虑深度优先,但会处理多继承中的冲突,确保类的继承关系是线性化的。 -
排除重复
在继承树中,每个类只会被访问一次。 -
保持继承顺序一致
子类的顺序会优先于父类,但父类的顺序会根据定义时的顺序进行保留。
二、查看 MRO
在 Python 中,可以使用以下方法查看一个类的 MRO:
Class.mro()
方法:返回一个类的 MRO 列表。help(Class)
:显示类的信息,其中包含 MRO。
示例:
class A:
def show(self):
print("A")
class B(A):
def show(self):
print("B")
class C(A):
pass
class D(B, C):
pass
print(D.mro())
# 输出: [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
help(D)
三、MRO 的应用场景
1. 多继承中方法冲突的处理
多继承时,如果多个父类有同名方法,MRO 会决定调用哪个父类的方法。
示例:
class A:
def show(self):
print("A")
class B(A):
def show(self):
print("B")
class C(A):
def show(self):
print("C")
class D(B, C): # 多继承
pass
d = D()
d.show()
# 输出: B
# MRO 确定 `D -> B -> C -> A -> object`
2. super()
的行为
super()
的调用遵循 MRO。当使用 super()
调用方法时,会按照 MRO 顺序继续查找下一个类的方法。
示例:
class A:
def greet(self):
print("Hello from A")
class B(A):
def greet(self):
print("Hello from B")
super().greet()
class C(A):
def greet(self):
print("Hello from C")
super().greet()
class D(B, C):
def greet(self):
print("Hello from D")
super().greet()
d = D()
d.greet()
# 输出:
# Hello from D
# Hello from B
# Hello from C
# Hello from A
MRO 确保了 super()
按顺序调用各个父类的方法。
四、MRO 的规则解析(C3 线性化算法)
C3 线性化算法是一种合并算法,确保继承顺序具有一致性和逻辑性。
步骤
- 从子类到父类按顺序依次列出所有父类。
- 确保子类优先于父类。
- 如果一个类有多个父类,按定义顺序列出父类。
- 保持父类中继承顺序的线性化。
示例:
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass
print(D.mro())
# 输出: [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
五、特殊情况
1. 菱形继承问题
菱形继承是指某个子类从两个父类继承,而两个父类又共同继承自一个祖先类的情况。Python 的 MRO 通过 C3 线性化算法解决了菱形继承问题,避免重复调用祖先类的方法。
示例:
class A:
def greet(self):
print("Hello from A")
class B(A):
def greet(self):
print("Hello from B")
super().greet()
class C(A):
def greet(self):
print("Hello from C")
super().greet()
class D(B, C):
pass
d = D()
d.greet()
# 输出:
# Hello from B
# Hello from C
# Hello from A
2. 无法线性化的继承关系
如果多继承中的顺序不符合 C3 线性化规则,Python 会报错。
示例:
class X: pass
class Y: pass
class A(X, Y): pass
class B(Y, X): pass
class C(A, B): pass # 会报错,因为无法确定 MRO 顺序
作者:江湖一条鱼