在Python中,对象名称前的单前导下划线和双前导下划线代表什么?


当前回答

如果真的想让变量成为只读的,IMHO最好的方法就是使用property(),只传递getter。有了property()我们可以完全控制数据。

class PrivateVarC(object):

    def get_x(self):
        pass

    def set_x(self, val):
        pass

    rwvar = property(get_p, set_p)  

    ronly = property(get_p) 

我知道OP问了一个稍有不同的问题,但由于我发现另一个问题是“如何设置私有变量”,标记为与此重复,所以我想在这里添加此附加信息。

其他回答

_var:python中带前导单下划线的变量是经典变量,旨在通知使用代码的其他人该变量应保留供内部使用。它们与经典变量有一点不同:在对定义它们的对象/模块进行通配符导入时,不会导入它们(定义__all__变量时除外)。如:#foo.pyvar=“var”_var=“_var”#巴.py从foo导入*print(dir())#已定义对象的列表,包含“var”但不包含“_var”打印(var)#varprint(_var)#name错误:未定义名称“_var”_:单下划线是前导单下划线变量的特殊情况。按照惯例,它被用作垃圾变量,以存储一个不打算稍后访问的值。它也不会通过通配符导入来导入。这个for循环打印“我不能在课堂上讲话”10次,并且永远不需要访问_变量。对于范围(10)内的_:打印(“我不能在课堂上讲话”)var_:单尾随下划线变量。它们是传统的变量,用于避免与Python关键字冲突。如:class_=“MyClassName”__var:双前导下划线变量(至少两个前导下划线,最多一个尾随下划线)。当用作类属性(变量和方法)时,这些变量会受到名称篡改:在类之外,python会将属性重命名为_<class_name>__<attribute_name>。例子:类MyClass:__an_attribute=“属性值”my_class=我的类()print(my_class.MyClass__an_attribute)#“属性值”print(my_class.__an_attribute)#AttributeError:“MyClass”对象没有属性“__an_aattribute”当用作类外部的变量时,它们的行为类似于单前导下划线变量。__var__:双前导和尾随下划线变量(至少两个前导和尾随底线)。也称为dunders。python使用此命名约定在内部定义变量。避免使用此约定来防止python更新可能产生的名称冲突。Dunder变量的行为类似于单前导下划线变量:它们在类中使用时不受名称篡改的影响,但不会在通配符导入中导入。

有时,您会看到一个带有前导下划线的元组,如

def foo(bar):
    return _('my_' + bar)

在本例中,发生的情况是,_()是本地化函数的别名,该函数根据语言环境对文本进行操作以将其转换为适当的语言等。例如,Sphinx这样做,您可以在导入中找到

from sphinx.locale import l_, _

在sphinx.locale中,_()被指定为某个本地化函数的别名。

到目前为止,答案很好,但缺少一些花絮。一个前导下划线不仅仅是一个约定:如果使用from foobar import*,并且foobar模块没有定义__all__列表,那么从模块导入的名称不包括前导下划线的名称。假设这主要是一个惯例,因为这个案例是一个相当模糊的角落;-)。

前导下划线约定不仅广泛用于私有名称,也广泛用于C++所称的受保护的名称,例如,完全打算由子类重写的方法的名称(即使是必须重写的方法,因为在基类中它们引发NotImplementedError!-)通常是单前导下划线名称,以向使用该类(或子类)实例的代码指示不打算直接调用所述方法。

例如,要使线程安全队列具有与FIFO不同的排队规则,可以导入queue,将queue.queue子类化,并重写_get和_put等方法;“客户端代码”从不调用这些(“钩子”)方法,而是调用(“组织”)公共方法,如put和get(这被称为模板方法设计模式——例如,请参见此处,以获取基于我关于该主题的演讲视频的有趣演示,并添加了摘要)。

编辑:会谈描述中的视频链接现已断开。你可以在这里和这里找到前两个视频。

你的问题很好,不仅仅是关于方法。模块中的函数和对象通常也以一个下划线作为前缀,也可以以两个下划线作为后缀。

例如,__double_underscore名称在模块中不会被篡改。如果从一个模块(从模块导入*)导入所有名称,则不会导入以一个(或多个)下划线开头的名称,也不会导入帮助(模块)中显示的名称。

.variable是半私有的,仅用于约定

.__variable通常被错误地认为是超级私有的,而它的实际含义只是为了命名mangle以防止意外访问[1]

.__variable__通常为内置方法或变量保留

您仍然可以访问__如果您非常想的话,可以对变量进行损坏。双下划线只是将变量命名为mangles或重命名为instance_类名__已损坏

例子:

class Test(object):
    def __init__(self):
        self.__a = 'a'
        self._b = 'b'

>>> t = Test()
>>> t._b
'b'

t.b是可访问的,因为它仅按惯例隐藏

>>> t.__a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__a'

找不到t.__a,因为它由于名称损坏而不再存在

>>> t._Test__a
'a'

通过访问实例_className__variable而不仅仅是双下划线名称,您可以访问隐藏值