在Python中重写“私有”方法
考虑一个有“私有”方法的类,比如:
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的动态特性,几乎没有什么是真正私有的;稍微检查一下,几乎任何东西都能被访问到。