在学习Python面向对象继承时,会遇到一个疑惑:父类普通方法会被子类同名方法覆盖,但如果把父类方法写成双下划线__xxx私有形式,子类就算写一模一样名字的方法,也完全覆盖不了父类内部调用,今天拆开底层原理一次性讲清楚。一、先看普通方法:子类可以轻松重写覆盖
示例代码
运行结果:
foo from son
底层原理
1.Son子类继承Base父类,并重写了同名foo方法;
2.执行s.test()时,会走到父类的test函数,内部执行self.foo();
3.Python 查找方法规则:实例自身 → 子类 Son → 父类 Base;
4.self是子类 Son 的实例,优先找到子类重写后的foo方法执行,这就是面向对象的多态特性;
5.重点:普通方法不会改名,父类、子类的方法都叫foo,子类同名会直接覆盖调用入口。
二、双下划线私有方法:子类永远无法覆盖父类内部调用
示例代码
运行结果
foo from base
核心底层机制:名称改写
Python有一条语法规则:以双下划线__开头、不以双下划线结尾的方法/属性,编译阶段会自动重命名改名公式:__方法名 → _当前类名__方法名
执行流程拆解
1. s.test()调用从父类继承来的test方法;
2. 方法内代码早已被固定改写为self._Base__foo();
3. 程序只会去寻找名为_Base__foo的方法,只会执行父类内部定义的私有逻辑;
4.子类写的__foo本质是另一个全新方法_Son__foo,完全不会干扰父类内部逻辑,实现父类核心方法不被子类篡改。
三、验证:打印实例属性字典,看清真实方法名
我们可以打印实例/类的命名空间,直观看到两个方法名字完全不一样:
输出里能清晰看到:
两个方法名完全独立,自然不存在重写覆盖一说。
四、总结
1.无下划线普通方法方法名称不会被改写,子类定义同名方法后,父类里self.方法()会动态匹配子类重写方法,支持多态。
2.双下划线__xxx私有方法编译阶段触发名称改写,自动拼接当前类名前缀;父类内部调用self.__xxx会被固定翻译为self._父类名__xxx,只会执行父类自身私有方法;子类的__xxx只会生成_子类名__xxx,和父类方法互不干扰,子类无法篡改父类内部逻辑。
补充小提示
Python的双下划线私有只是语法模拟私有,并非真正强制不可访问。如果硬要在外部调用父类私有方法,可以手动使用改写后的真实名称:s._Base__foo()
日常开发不推荐这种写法,会破坏封装性。