【问题标题】:Double underscore in pythonpython中的双下划线
【发布时间】:2017-07-24 19:53:54
【问题描述】:
class A(object):
    def __get(self):
        pass

    def _m(self):
        return self.__get()


class B(A):
    def _m(self):
        return str(self.__get())

print(A()._m())
print(B()._m())

为什么print(A()._m()) 打印None,但print(B()._m()) 引发AttributeError: 'B' object has no attribute '_B__get'

我认为双下划线可以防止方法覆盖。

更新

您写道__get 是私有的。

那么为什么以下工作?

class A(object):
    def __get(self):
        pass

    def _m(self):
        return self.__get()


class B(A):
    pass

print(A()._m())
print(B()._m())

为什么这段代码没有引发AttributeError 并打印None 两次?

【问题讨论】:

  • Name mangling。您在B 中对self.__get() 的调用实际上是在调用self._B__get(),它不存在。除非您想要这种行为,否则不要使用前导双下划线。
  • 查看what is the meaning of a single and a double underscore before an object name和一些链接的问题,因为有一些详细的解释。
  • 重新更新:因为您正在从类 A 中定义的方法调用 __get。这在任何支持私有概念的语言中都是完全合法的——事实上,这是私有的最常见用例方法。

标签: python


【解决方案1】:

前导双下划线名称为private(表示派生类不可用)

这不是万无一失的。它是通过修改名称来实现的。 Python Documentation 说:

__spam 形式的任何标识符(至少两个前导下划线, 最多一个尾随下划线)在文本上替换为 _classname__spam,其中 classname 是当前类名,去掉了前导下划线。这种修改是不加考虑的 到标识符的句法位置,所以它可以用来 定义类私有实例和类变量、方法、变量 存储在全局变量中,甚至变量存储在实例中。私人的 这个类在其他类的实例上。

因此,__get 实际上在 A 类中被修改为 _A__get。当 B 类尝试引用 __get 时,它被修改为不匹配的 _B__get

换句话说,在 Xyzzy 类中定义的 __plugh 的意思是“除非你以 Xyzzy 类的身份运行,否则你不得触摸 __plugh。”

【讨论】:

  • “前导双下划线名称为private(表示派生类不可用)”请不要这样做。在 Python 中有一个叫做 private 的注释,这些名称是 (pseudoprivate) 而不是私有的。
  • @direprobs 前导下划线的目的是对除定义类之外的所有人隐藏符号。在许多其他语言中,这个概念被称为“私有”。因此,我使用了一个词来表示应该很好理解的概念。我还解释了实现细节并提到了缺乏万无一失。您还建议如何传达这个概念?
  • 这就是问题所在。例如,私有这个词会暗示私有,就像它在 Java 中一样,不能从类外部访问该变量。您说派生类无法使用该变量,这是绝对错误的。
  • 请注意,我引用的官方python文档称这个概念--嗯--'class-private'
【解决方案2】:

对于__methodName()类A的成员函数:

  • 要从A类外部调用该成员函数,只能调用_A__methodName()(尝试调用__methodName()会报错)

  • 要在 A 类中调用该成员函数,可以同时使用 _A__methodName()__methodName()

【讨论】:

    猜你喜欢
    • 2021-11-28
    • 2012-11-09
    • 2016-12-03
    • 2012-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多