在Python中覆盖"私有"方法

Ern*_*t A 10 python oop methods subclass private-members

考虑使用"私有"方法的类,例如:

class Foo(object):
    def __init__(self):
        self.__method()
    def __method(self):
        print('42')
Run Code Online (Sandbox Code Playgroud)

当我尝试子类化Foo和覆盖方法时__method,可以看到它Foo.__method仍然被调用,而不是MoreFoo.__method.

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

>>> MoreFoo()
42
<__main__.MoreFoo object at 0x7fb726197d90>
Run Code Online (Sandbox Code Playgroud)

覆盖这种方法的方法是什么?

Mar*_*ers 21

使用双下划线名称约定的是为了防止子类从(意外地)重写方法.

如果你不得不重写它,有人犯了严重的类设计错误.你可以通过命名你的对象来做到这一点:

def _Foo__method(self):
Run Code Online (Sandbox Code Playgroud)

您在方法名称前面加上一个下划线和定义的类名(在本例中为前缀_Foo).使用双下划线重命名方法和属性的过程称为私有名称重整.

如果要定义一个在子类中仍然可以覆盖的"私有"方法,通常会使用一个下划线代替(def _method(self):).

由于它的动态特性,Python中几乎没有任何东西是真正私有的; 有点内省,几乎可以达到任何目的.


Gar*_*tty 9

双下划线前缀调用名称修改,它等同于私有方法.它专门设计用于避免被子类覆盖(在这种情况下,方法名称变为_Foo__method).

如果您有一个实现细节,请在其前面加上一个下划线,这是Python方法的普遍接受的标志,不能在外部使用.没有强制执行此操作,因为这不是Python的功能.


mgi*_*son 5

我相信你会做这样的事情:

class MoreFoo(Foo):
    def _Foo__method(self):
        print('41')
Run Code Online (Sandbox Code Playgroud)

记录在案

任何形式的标识符__spam(至少两个前导下划线,最多一个尾随下划线)在文本上替换为_classname__spam,其中classname是去除前导下划线的当前类名。

但是原始类的设计者认为你不需要做这样的事情,因为很难用子类覆盖是双下划线开始的重点:

名称修改有助于让子类覆盖方法而不破坏类内方法调用。