Python双下划线名称修饰

9

我对这种行为感到有些困惑(使用Python 3.2):

class Bar:
    pass

bar = Bar()
bar.__cache = None
print(vars(bar))        # {'__cache': None}

class Foo:
    def __init__(self):
        self.__cache = None

foo = Foo()
print(vars(foo))        # {'_Foo__cache': None}

我已经了解了双下划线如何导致属性名被“破坏”,但我本来希望在上述两种情况下都有相同的名称破坏。

一个对象名称前单下划线和双下划线的含义是什么?

这里发生了什么事情,有什么想法吗?


4
混淆的目的正是为了防止第二种情况的正确运行。意图是隐藏属性不让外部代码访问到。 - millimoose
2个回答

13

名称重整发生在class语句的评估过程中。对于Bar__cache属性不作为类的一部分定义,而是在事后添加到特定对象中。

(实际上,这可能并不完全正确。名称重整可能会在评估__new__方法期间发生;我不知道。但无论如何,您的__cache都是显式地添加到单个对象中,而不是由类代码添加的。)


8
编译时名称被改变了。你可以使用dis.dis()函数来查看,只需运行 import dis; dis.dis(Foo.__init__) 就可以看到名称已经被改变了。 - Martijn Pieters

11

来自文档

私有名称改名:当在类定义中以两个或多个下划线字符开头且不以两个或多个下划线结束的标识符被文本形式使用时,它被视为该类的私有名称。在生成代码之前,私有名称将转换为更长的形式。转换会在名称前插入类名,在删除前导下划线并在类名前插入单个下划线。例如,在名为Ham的类中出现的标识符__spam将被转换为_Ham__spam。该转换与标识符使用的语法上下文无关。如果转换后的名称非常长(超过255个字符),则可能会发生实现定义的截断。如果类名仅包含下划线,则不执行转换。

您是在类已定义后分配属性


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接