Python 方法名带双下划线会被覆盖吗?

32 投票
2 回答
24593 浏览
提问于 2025-04-16 20:06

看看这个。注意类 B 是如何重写类 Aa() 方法的。

In [1]: class A(object):
   ...:     def __init__(self):
   ...:         self.a()
   ...:     def a(self):
   ...:         print "A.a()"
   ...:         
   ...:         

In [2]: class B(A):
   ...:     def __init__(self):
   ...:         super(B, self).__init__()
   ...:     def a(self):
   ...:         print "B.a()"
   ...:         
   ...:         

In [3]: b = B()
B.a()

这没什么意外。

现在,再看看这个。注意现在被重写的方法是 __a()

In [7]: class A(object):
   ...:     def __init__(self):
   ...:         self.__a()
   ...:     def __a(self):
   ...:         print "A.__a()"
   ...:         
   ...:         

In [8]: class B(A):
   ...:     def __init__(self):
   ...:         super(B, self).__init__()
   ...:     def __a(self):
   ...:         print "B.__a()"
   ...:         
   ...:         

In [9]: b = B()
A.__a()

这个行为让我感到惊讶。

有没有人能解释一下为什么会调用 A.__a() 而不是 B.__a()

关于 __a 有什么 __special__ 的地方吗?

更新:在阅读了Sean的回答后,我想看看能否重写这个名字被修改过的方法,结果是这样的:

In [11]: class B(A):
   ....:     def __init__(self):
   ....:         super(B, self).__init__()
   ....:     def _A__a(self):
   ....:         print "B._A__a()"
   ....:         
   ....:         

In [12]: b = B()
B._A__a()

2 个回答

1
In [1]: class A(object):
...:     def __init__(self):
...:         self.a()
...:     def a(self):
...:         print "A.a()"
...:
...:     __str__ = a
...:         

In [2]: class B(A):
...:     def __init__(self):
...:         super(B, self).__init__()
...:     def a(self):
...:         print "B.a()"
...:         
...:         

In [3]: b = B()
        print str(b)
   A.a()

你需要在B里面重新声明一下__str__

34

以__*开头的关键词是类的私有名称。

http://docs.python.org/reference/lexical_analysis.html#reserved-classes-of-identifiers

引用内容:

在类定义的上下文中使用的这类名称,会被改写成一种特殊的形式,以帮助避免基类和派生类之间“私有”属性的名称冲突。

私有名称改写(强调部分):

私有名称改写:当一个在类定义中出现的标识符以两个或更多的下划线开头,并且不以两个或更多的下划线结尾时,它被视为该类的私有名称。在生成代码之前,私有名称会被转换为一种更长的形式。这个转换会在名称前面加上类名,同时去掉前面的下划线,并在类名之前加一个下划线。例如,在名为Ham的类中出现的标识符__spam会被转换为_Ham__spam。这个转换与标识符使用的语法上下文无关。如果转换后的名称非常长(超过255个字符),可能会进行截断。如果类名仅由下划线组成,则不会进行任何转换。

http://docs.python.org/reference/expressions.html#atom-identifiers

这意味着在后台,B.__a()会被转换成类似B._B__a()的形式。

撰写回答