Python派生类中私有属性解析机制及代码执行流程咨询
为什么Tire实例调用area()没有使用_Tire__perimeter?
让我一步步拆解这段代码的执行流程,帮你搞清楚核心问题所在——本质是Python的**名称修饰(Name Mangling)**规则和方法调用时的解析逻辑。
先明确名称修饰的核心规则
Python中,以双下划线__开头的方法/属性,会在类定义的阶段被自动重命名为_类名__方法名的形式。这个重命名是固定的,只和定义该方法的类有关,和调用方法的实例类型无关。
比如:
- Circle类里的
__perimeter,会被重命名为_Circle__perimeter - Tire类里的
__perimeter,会被重命名为_Tire__perimeter
逐行拆解t = Tire(20); print(t.area())的执行流程
创建Tire实例
t- 因为Tire没有重写
__init__,所以调用父类Circle的__init__方法,把t.radius设置为20。
- 因为Tire没有重写
调用
t.area()- Tire没有重写
area方法,所以执行的是Circle类中的area方法。 - 看Circle的
area代码:p = self.__perimeter()——这里的__perimeter在Circle类定义时已经被重命名为_Circle__perimeter,所以这句代码实际等价于p = self._Circle__perimeter()。 - 此时
self是Tire实例,但调用的是_Circle__perimeter(Circle类的私有方法),返回值是2.0 * math.pi * 20 = 40π。 - 后续计算面积:
math.pi * (p *0.5/math.pi)**2 = math.pi * (20)**2 = 400π ≈ 1256.637,这就是你看到的实际结果。
- Tire没有重写
为什么没用到Tire的
__perimeter?- Tire类里的
_Tire__perimeter只有在Tire类定义的方法中被调用__perimeter时才会触发。比如Tire的perimeter方法里的self.__perimeter(),会被重命名为self._Tire__perimeter(),调用的是Tire自己的私有方法。 - 但Circle的
area方法是在Circle类里定义的,里面的__perimeter已经被绑定到_Circle__perimeter,不管调用它的实例是Circle还是Tire,都会去找_Circle__perimeter方法。
- Tire类里的
验证:如果重写Tire的area方法会怎样?
如果给Tire添加一个area方法:
class Tire(Circle): def perimeter(self): return self.__perimeter() def __perimeter(self): return Circle.perimeter(self)*1.25 def area(self): p = self.__perimeter() return math.pi * (p *0.5/math.pi)**2
此时调用t.area(),self.__perimeter()会被重命名为self._Tire__perimeter(),计算出来的面积就是基于50π的结果,和你最初的预期一致。
总结
名称修饰是类定义阶段的静态处理,不是运行时的动态解析。在哪个类里写的__xxx,就会被绑定到_类名__xxx,和调用该方法的实例类型无关。这也是Python私有方法的设计初衷:确保父类的私有方法不会被子类意外覆盖,同时子类也可以拥有自己同名的私有方法,互不干扰。
内容的提问来源于stack exchange,提问作者ghost
相关产品推荐
相关产品推荐

