在Python中重写“私有”方法

23 投票
3 回答
18673 浏览
提问于 2025-04-17 16:00

考虑一个有“私有”方法的类,比如:

class Foo(object):
    def __init__(self):
        self.__method()
    def __method(self):
        print('42')

当我尝试创建一个叫做 MoreFoo 的子类,并重写 __method 方法时,我发现 Foo.__method 仍然会被调用,而不是 MoreFoo.__method

class MoreFoo(Foo):
    def __method(self):
        print('41')

>>> MoreFoo()
42
<__main__.MoreFoo object at 0x7fb726197d90>

那么,怎样才能重写这样一个方法呢?

3 个回答

6

我认为你可以这样做:

class MoreFoo(Foo):
    def _Foo__method(self):
        print('41')

就像文档中说明的那样。

任何形式为__spam的标识符(至少有两个前导下划线,最多一个后导下划线)会被文本替换为_classname__spam,其中classname是当前类的名称,前面的下划线会被去掉。

但是,原始类的设计者认为你不应该需要这样做,因为让子类难以重写是双下划线的初衷:

名称改名有助于让子类重写方法,而不会破坏类内部的方法调用。

16

在Python中,如果一个方法名前面有两个下划线,这会触发一种叫做名字改编的机制。这并等同于私有方法,它的设计目的是为了防止子类去重写这个方法(在这种情况下,这个方法的名字会变成_Foo__method)。

如果你有一些实现细节,可以在方法名前加一个下划线。这是大家公认的标志,表示这个方法不应该被外部使用。不过,Python并不会强制执行这一点,因为这不是Python的工作方式。

41

使用双下划线命名规则的目的是为了防止子类(不小心)覆盖这个方法。

如果你非要覆盖这个方法,那说明类的设计有问题。不过你还是可以做到,只需要这样命名你的对象:

def _Foo__method(self):

在方法名前加一个下划线,并加上定义这个类的名字(在这个例子中就是加上_Foo)。把方法和属性用双下划线重命名的过程叫做私有名称改名

如果你想定义一个“私有”的方法,但又希望在子类中可以覆盖,通常只需要用一个下划线命名就可以了(def _method(self):)。

由于Python的动态特性,几乎没有什么是真正私有的;稍微检查一下,几乎任何东西都能被访问到。

撰写回答