17

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

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

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

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

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

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

4

3 回答 3

33

使用双下划线命名约定的目的是防止子类(意外)覆盖该方法

如果你无论如何必须重写它,那么有人犯了一个严重的类设计错误。您仍然可以这样做,只需这样命名您的对象:

def _Foo__method(self):

您在方法名称前加上一个下划线和定义类名(因此在这种情况下以 为前缀_Foo)。使用双下划线重命名方法和属性的过程称为私有名称修改

如果你想定义一个在子类中仍然可以被覆盖的“私有”方法,你通常坚持使用一个下划线来代替(def _method(self):)。

由于其动态特性,Python 中几乎没有什么是真正私有的。稍加反省,几乎可以达到任何目标。

于 2013-02-15T15:45:03.513 回答
13

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

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

于 2013-02-15T15:44:45.667 回答
7

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

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

记录的那样。

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

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

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

于 2013-02-15T15:45:01.623 回答