飞翔飞翔
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • 学习路径
  • 第1章 Python简介

    • Python是什么
    • 安装与运行
    • 交互式解释器
    • 注释与编码规范
  • 第2章 变量与数据类型

    • 变量与对象
    • 整数 int
    • 浮点数 float
    • 复数 complex
    • 布尔值 bool
    • 字符串 str
    • 空值 None
    • 类型转换
  • 第3章 运算符与表达式

    • 算术运算符
    • 比较运算符
    • 赋值运算符
    • 逻辑运算符
    • 位运算符
    • 身份与成员运算符
    • 海象运算符
    • 运算符优先级
  • 第4章 流程控制

    • if 语句
    • if-else 语句
    • if-elif-else 语句
    • match-case 语句
    • 条件表达式(三元运算符)
    • while 循环
    • for 循环
    • range 函数
    • break 与 continue
    • 循环的 else 子句
    • pass 语句
  • 第5章 数据结构

    • 列表创建与索引
    • 列表方法
    • 列表推导式
    • 元组
    • 序列解包
    • 集合
    • 字典创建与访问
    • 字典方法
    • 字典推导式
    • range 对象
  • 第6章 函数

    • 定义函数
    • 位置参数与关键字参数
    • 默认参数
    • 可变参数
    • 解包实参
    • 函数返回值
    • lambda 表达式
    • 文档字符串与注解
    • 作用域与命名空间
    • global 与 nonlocal
  • 第7章 模块与包

    • 模块导入
    • 模块搜索路径
    • 包与相对导入
    • 标准库概览
  • 第8章 文件与输入输出

    • 文件读写
    • 上下文管理器
    • 字符串格式化
    • JSON 与 CSV
  • 第9章 面向对象

    • 类与对象
    • 方法
    • 实例变量与类变量
    • 私有变量
    • 继承
    • 多重继承
    • 魔术方法
    • 属性装饰器
    • 数据类 dataclass
  • 第10章 异常处理

    • 语法错误与异常
    • try-except
    • 异常链与 raise
    • 清理操作
    • 自定义异常
  • 第11章 迭代器与生成器

    • 迭代器协议
    • 生成器
    • 生成器表达式
    • 迭代工具
  • 第12章 高级特性

    • 装饰器
    • 函数式编程
  • 第13章 工程实践

    • 测试与调试
    • 代码质量
    • 虚拟环境

继承

继承是面向对象的核心机制之一。Python 的继承语法简洁,但底层行为与 C++ 等静态语言有显著差异:所有实例方法本质上都是虚方法,方法解析支持动态调整,且内置类型也可被用户扩展。

单继承语法

派生类定义将基类置于类名后的圆括号中:

class Base:
    def __init__(self, value):
        self.value = value
    
    def show(self):
        return f'Base: {self.value}'

class Derived(Base):
    def double(self):
        return self.value * 2

d = Derived(21)
print(d.show())     # Base: 21 —— 继承自 Base
print(d.double())   # 42      —— Derived 自有方法

基类名称必须能在定义派生类的作用域中被解析。当基类位于其他模块时,使用模块限定名:

# class Derived(some_module.Base):
#     pass

派生类的实例化没有任何特殊之处。Derived() 创建空对象后,如果定义了 __init__,则调用它。若派生类未定义 __init__,解释器会自动沿继承链查找并使用第一个找到的基类 __init__。

方法重写

派生类可以定义与基类同名的方法来重写(override)基类实现。由于 Python 的方法在调用同一对象的其他方法时没有特殊权限,基类方法调用另一方法时,实际执行的可能是派生类中重写后的版本。

class Base:
    def greet(self):
        return f'Hello, {self.name()}'
    
    def name(self):
        return 'Base'

class Derived(Base):
    def name(self):           # 重写 name
        return 'Derived'

print(Derived().greet())   # Hello, Derived

这与 C++ 中需要显式声明 virtual 不同——Python 中所有方法默认都是虚方法。设计基类时,必须意识到 self 引用的始终是实际实例所属的最低层派生类。

调用基类方法

重写方法通常需要扩展而非完全替换基类逻辑。最直接的方式是通过类名显式调用:

class Base:
    def __init__(self, value):
        self.value = value
    
    def report(self):
        return f'value={self.value}'

class Derived(Base):
    def __init__(self, value, extra):
        Base.__init__(self, value)    # 显式调用基类构造
        self.extra = extra
    
    def report(self):
        base = Base.report(self)      # 显式调用基类方法
        return f'{base}, extra={self.extra}'

d = Derived(10, 'bonus')
print(d.report())   # value=10, extra=bonus

这种方式直观,但存在局限:仅当基类可在全局作用域中以该名称访问时才有效;在多重继承场景中,无法正确处理菱形结构中的协同调用。

super() 函数

super() 返回一个代理对象,将方法调用委托给基类。在单继承中,它等价于通过基类名调用,但写法更健壮:

class Derived(Base):
    def __init__(self, value, extra):
        super().__init__(value)       # 无需硬编码 Base
        self.extra = extra

super() 的零参数形式(Python 3 新增)会自动推断当前类和实例。在方法内部,super() 等价于 super(CurrentClass, self)。

super() 的真正威力体现在多重继承中(详见多重继承章节),它能按照方法解析顺序(MRO)找到下一个应该被委托的类,而不仅仅是直接父类。

方法解析顺序(MRO)

每个类都有一个 __mro__ 属性,它是一个元组,按照属性查找的顺序列出该类及其所有基类。在单继承中,MRO 就是从子类到父类再到 object 的线性链条。

class A:
    pass

class B(A):
    pass

class C(B):
    pass

print(C.__mro__)
# (<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

当访问实例属性时,Python 首先在实例的 __dict__ 中查找;若未找到,则沿 __mro__ 依次在每个类的 __dict__ 中查找,直到 object。

类还提供了 mro() 方法,返回与 __mro__ 相同的列表(但为列表类型)。子类可以通过重写 mro() 来自定义方法解析顺序,但这极为罕见且容易出错。

isinstance 与 issubclass

isinstance(obj, cls) 检查对象是否是指定类或其派生类的实例。它考虑继承关系,因此比 type(obj) is cls 更灵活:

class Animal:
    pass

class Dog(Animal):
    pass

d = Dog()
print(isinstance(d, Dog))      # True
print(isinstance(d, Animal))   # True —— 考虑继承
print(type(d) is Dog)          # True
print(type(d) is Animal)       # False —— type 不考虑继承

isinstance 的第二个参数可以是元组,用于检查多个类型中的任意一个:

print(isinstance(d, (Dog, int, str)))   # True

issubclass(cls, base) 检查类继承关系:

print(issubclass(Dog, Animal))    # True
print(issubclass(bool, int))      # True —— bool 继承自 int
print(issubclass(float, int))     # False
print(issubclass(Dog, (Animal, int)))   # True

注意 issubclass 要求第一个参数必须是类(或类型),传入实例会引发 TypeError。

继承内置类型

Python 允许用户类继承内置类型,这是与 C++ 和 Modula-3 的重要区别。继承 list、dict、str 等类型可以方便地扩展功能:

class TypedList(list):
    """只允许存储特定类型的元素"""
    
    def __init__(self, type_, iterable=None):
        self.type_ = type_
        super().__init__()
        if iterable:
            for item in iterable:
                self.append(item)
    
    def append(self, item):
        if not isinstance(item, self.type_):
            raise TypeError(f'Expected {self.type_.__name__}, got {type(item).__name__}')
        super().append(item)

nums = TypedList(int, [1, 2, 3])
nums.append(4)
print(nums)           # [1, 2, 3, 4]
# nums.append('a')    # TypeError: Expected int, got str

继承内置类型时需要注意:某些内置方法(如 list.__init__)可能不调用被重写的 append,导致类型检查被绕过。对于要求严格的场景,通常更推荐组合(composition)而非继承。

上一页
私有变量
下一页
多重继承