Python类继承中双下划线防覆盖机制解析
本文深入解析Python中双下划线开头的类属性与方法为何在继承时不被覆盖。通过对比单下划线与双下划线的行为,揭示Python通过名称修饰(Name Mangling)将__attr转换为_classname__attr的实现机制,并说明其在防止子类意外覆盖父类私有成员中的作用及访问方式。
Python类继承中的方法覆盖问题
在Python面向对象编程中,继承是常用的代码复用手段。以如下代码结构为例:
class Info:
def __init__(self):
pass
def calc_age(self):
print('我是父类的方法')
class PeopleInfo(Info):
def __init__(self):
super().__init__()
def calc_age(self):
print(123456)
若使用PeopleInfo类实例化对象并调用其calc_age方法,运行结果会显示子类方法被成功调用,具体表现如截图所示:
由此可见,父类Info中的calc_age方法被子类PeopleInfo中同名方法完全覆盖。
__init__是否会被覆盖的验证
上述现象属于基础常识。接下来探讨一个关键问题:子类PeopleInfo中的__init__方法是否会覆盖父类Info中的__init__?
为验证该假设,我们进行如下测试:
class Info:
def __init__(self):
print('我是父类的__init__')
def calc_age(self):
print('我是父类的方法')
class PeopleInfo(Info):
def __init__(self):
super().__init__()
print('我是之类的初始化方法')
def calc_age(self):
print(123456)
运行结果如截图所示:
观察发现,父类与子类的__init__方法均被执行。
有人可能解释称,因子类__init__中调用了super().__init__(),导致父类方法在子类完全覆盖前已执行,随后才被覆盖。
自定义方法测试与双下划线特性
这种解释并不准确。为证明该现象与super().__init__()无关,我们改用自定义方法进行测试:
class Info:
def __init__(self):
pass
def __calc_age(self):
print('我是父类的方法')
def run_father(self):
self.__calc_age()
class PeopleInfo(Info):
def __init__(self):
super().__init__()
pass
def __calc_age(self):
print(123456)
def run_son(self):
self.__calc_age()
运行结果如截图所示:
结果显示,父类与子类的__calc_age方法均成功执行。
原因在于,Python中凡以双下划线开头的方法或属性,均被视为类的私有成员。在继承场景下,即使子类存在同名双下划线开头的方法或属性,也不会覆盖父类对应成员。
此外,这些双下划线开头的私有方法或属性可在类内部被其他方法自由调用,但在实例对象层面无法直接访问,具体表现如截图所示:
双下划线防覆盖的实现机制
Python如何实现这一机制?实际上,Python仅对名称进行了修改。通过dir函数查看实例对象kingname的属性列表,结果如截图所示:
请注意方框标注内容:_Info__calc_age对应父类__calc_age,_PeopleInfo__calc_age对应子类__calc_age。Python通过在双下划线私有方法或属性前添加_类名前缀进行名称修饰(Name Mangling),确保父子类方法名不同,从而避免覆盖。
私有成员的强制访问方式
尽管规范上不建议外部访问双下划线私有方法或属性,但若需强制访问,可使用修改后的名称:
kingname = PeopleInfo()
kingname._PeopleInfo__calc_age() # 强行调用子类的私有方法
kingname._Info__calc_age() # 强行调用父类的私有方法
运行结果如截图所示:
总结
以上介绍了Python利用双下划线防止类属性被覆盖的原理与机制,希望能为读者提供有益参考。如有任何疑问,欢迎留言讨论,作者将及时回复。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













