python继承是动态属性查找机制,非代码复制;公有字段子类可自由访问,受保护字段约定内部使用,私有字段经名称重整后子类无法直接访问;方法无真正私有,仅靠命名约定和重整实现“隐藏”;子类__init__需显式调用父类初始化;多继承按mro顺序决定同名成员优先级。

Python 中的继承不是简单地“复制粘贴”父类代码,而是一种动态的属性查找机制。字段(属性)和方法的访问行为受继承链、命名约定、调用方式共同影响,尤其在涉及私有成员、重写和多继承时容易产生误解。
字段如何被子类访问:公有、受保护与私有
字段是否能被子类直接使用,取决于其命名方式,而非声明位置:
-
公有字段(如
self.name):子类可自由读写,无访问限制; -
受保护字段(如
self._age,单下划线开头):约定为“内部使用”,子类可以访问,但应避免外部直接修改; -
私有字段(如
self.__score,双下划线开头):Python 会触发名称重整(name mangling),实际变为self._ClassName__score。子类无法通过self.__score访问父类该字段,必须用重整后的名称(不推荐)或通过父类提供的公有/受保护接口(如 getter 方法)间接访问。
方法隐藏的本质是名称重整,不是访问控制
Python 没有真正的“私有方法”,所谓“隐藏”仅靠命名约定和名称重整实现:
-
def __helper(self):在父类中定义 → 子类调用self.__helper()会报AttributeError,因为子类找不到该重整名; - 子类若定义同名
__helper,它重整为_SubClass__helper,与父类的_ParentClass__helper完全不同,二者互不影响; - 真正想“隐藏”的逻辑,应封装在公有方法内,由父类统一暴露接口,而不是依赖双下划线“躲”起来。
子类初始化时字段继承的关键细节
子类 __init__ 不自动调用父类 __init__,字段继承需显式处理:
- 若父类有必需参数(如
name,age),子类实例化时未传入或未传递给父类,会导致字段缺失或AttributeError; - 推荐统一用
super().__init__(...)调用,尤其在多重继承中可保证 MRO 顺序下的正确初始化; - 若手动用
Parent.__init__(self, ...),需确保所有父类都被显式调用(多重继承时易遗漏),且参数顺序必须与各父类构造函数签名严格匹配。
多继承中同名字段/方法的“就近”与 MRO 决定权
当多个父类含同名字段或方法时,Python 不按“谁先定义”决定,而是严格遵循 MRO(Method Resolution Order):
- 可通过
ClassName.__mro__查看解析顺序,例如class C(A, B): pass的 MRO 是(C, A, B, object); - 字段查找从左到右:若
A和B都有self.role = "teacher",C实例访问.role时取A中的值; - 方法调用同理,
c.method()执行的是 MRO 中第一个出现该方法的类中的版本; - 注意:字段赋值(
self.role = "student")只影响当前实例,不会覆盖父类字段定义,但会遮蔽后续同名字段查找。











