Python子类如何访问父类的双下划线(dunder)方法?
问题描述
我定义了如下类结构:
class Parent(object): def __init__(self, x): self.x = x def __add(self,y): return self.x + y def addition(self,y): return self.__add(y) class Children(Parent): def add(self,y): return self.__add(y)
实例化后,Parent和Children的addition方法都能正常调用:
p = Parent(2) p.addition(4) # 正常运行 c = Children(5) c.addition(4) # 正常运行
但以下调用都会抛出AttributeError:
p.__add(5) # 报错:'Parent' object has no attribute '__add' c.add(4) # 报错:'Children' object has no attribute '_Children__add'
其中第一种报错符合预期,但子类无法访问父类的__add方法让我困惑。实际场景中,我的父类包含一个__check_password方法,希望设为“私有”,同时能让多个子类调用这个方法。
原因分析
Python中,以双下划线__开头的方法会触发**名称修饰(Name Mangling)**机制:Python解释器会自动将这类方法重命名为_类名__方法名的格式。比如Parent类中的__add会被重命名为_Parent__add,而在Children类中调用self.__add时,Python会去寻找_Children__add,但这个方法并不存在,所以报错。
这种机制的目的是避免子类意外覆盖父类的私有方法,确保父类的内部实现不被子类破坏。
解决方案
方案1:使用单下划线作为“保护”方法(推荐)
Python中没有真正的私有方法,单下划线_开头的方法是约定俗成的“保护方法”——外部代码不应该直接调用,但子类可以正常访问。把父类的方法改成单下划线开头即可:
class Parent(object): def __init__(self, x): self.x = x def _add(self,y): # 改为单下划线 return self.x + y def addition(self,y): return self._add(y) class Children(Parent): def add(self,y): return self._add(y) # 子类直接调用
对应到你的实际场景,把__check_password改成_check_password,子类就能直接调用,同时外部代码也会遵循约定不随意调用这个方法。
方案2:直接调用被修饰后的方法(不推荐)
如果你坚持使用双下划线,可以在子类中直接调用父类被修饰后的方法名_Parent__add:
class Children(Parent): def add(self,y): return self._Parent__add(y) # 直接调用重命名后的方法
但这种方式不推荐,因为它破坏了封装性,一旦父类的类名修改,子类中的调用代码也需要同步修改,维护成本高。
方案3:父类提供公共/保护接口封装私有方法
如果父类的双下划线方法必须保留,可以在父类中提供一个保护级别的接口方法,让子类通过这个接口调用私有方法:
class Parent(object): def __init__(self, x): self.x = x def __add(self,y): return self.x + y def addition(self,y): return self.__add(y) def _call_add(self, y): # 提供给子类的保护接口 return self.__add(y) class Children(Parent): def add(self,y): return self._call_add(y) # 子类调用保护接口
内容的提问来源于stack exchange,提问作者FraSchelle

