Python继承:为什么方法中的self会指向子类实例?
运行逻辑说明
你对super的作用存在常见误解,整个执行流程可以拆解为几个核心Python面向对象规则,结合代码执行步骤就能搞清楚结果为什么是2:
核心规则
self的指向永远和实例的实际类型一致,和方法定义在哪个类无关。只要你创建的是C类的实例,不管后续调用的__init__是定义在B类还是A类,方法接收到的self始终是这个C类实例,不会变成父类的实例。- Python的属性查找是动态按MRO(方法解析顺序)执行的:查找
self.xxx时,会先查实例自身的属性,没有就查实例所属类的类属性,再顺着类的继承链依次往上找,不会因为当前代码写在父类里,就从父类开始找属性。 super不是硬引用当前类的父类,它返回的是一个绑定了当前实例的代理对象,方法查找是沿着实例对应类的MRO顺序向后遍历,不会改变self的指向。
逐行执行流程拆解
- 执行
c = C()时,首先创建C类的实例,触发C类定义的__init__方法,此时方法内的self就是刚创建的C类实例。 - C的
__init__中调用super().__init__(),super沿着C的MRO(C -> B -> A -> object)找到下一个实现了__init__的类是B,因此调用B类定义的__init__,注意此时方法的调用接收者还是原来的C类实例,self没有发生变化。 - 进入B的
__init__后执行self.x取值:- 先查C实例自身有没有x属性:没有
- 再查实例所属的C类,发现C类定义了类属性
x = 2,直接返回2,不会继续往B类查找
- 取到的x=2被传给A类的
__init__,赋值给实例的attr属性,因此最终c.attr的值就是2。
验证方式
如果想拿到x=1的结果,直接创建B类的实例即可:
b = B() print(b.attr) # 输出1
此时self是B类的实例,查找self.x时会在B类找到x=1,结果就符合预期。你也可以在B的__init__中加一句print(type(self)),创建C实例时会看到输出为<class '__main__.C'>,直接验证self的指向。
内容的提问来源于stack exchange,提问作者actual_panda
相关产品推荐
相关产品推荐

