协慌网

登录 贡献 社区

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

有人可以解释在 Python 中对象名称之前有前导下划线的确切含义吗?另外,解释单个和双重前导下划线之间的区别。此外,无论所讨论的对象是变量,函数,方法等,这个含义是否保持不变?

答案

单下划线

具有前导下划线的类中的名称只是向其他程序员指示该属性或方法是私有的。但是,名称本身并没有什么特别之处。

引用PEP-8

_single_leading_underscore:弱 “内部使用” 指标。例如, from M import *不会导入名称以下划线开头的对象。

双下划线(名称管理)

Python 文档

形式__spam任何标识符(至少两个前导下划线,最多一个尾随下划线)在文本上用_classname__spam替换,其中classname是当前类名,其中前导下划线被剥离。这种修改是在不考虑标识符的句法位置的情况下完成的,因此它可以用于定义类私有实例和类变量,方法,存储在全局变量中的变量,甚至存储在实例中的变量。在其他类的实例上对此类私有。

并在同一页面发出警告:

名称修改旨在为类提供一种简单的方法来定义 “私有” 实例变量和方法,而不必担心派生类定义的实例变量,或者通过类外部的代码来修改实例变量。请注意,修剪规则主要是为了避免事故; 确定的灵魂仍然可以访问或修改被视为私有的变量。

>>> class MyClass():
...     def __init__(self):
...             self.__superprivate = "Hello"
...             self._semiprivate = ", world!"
...
>>> mc = MyClass()
>>> print mc.__superprivate
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: myClass instance has no attribute '__superprivate'
>>> print mc._semiprivate
, world!
>>> print mc.__dict__
{'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}

到目前为止优秀的答案,但一些花絮丢失。单个前导下划线并不仅仅是一个约定:如果使用from foobar import * ,并且模块foobar没有定义__all__列表,则从模块导入的名称包括具有前导下划线的名称。让我们说它主要是一种惯例,因为这个案例是一个非常模糊的角落;-)。

前导下划线约定不仅被广泛用于私有名称,而且被广泛用于 C ++ 将其称为受保护的名称 - 例如,完全打算被子类覆盖的方法的名称(甚至是那些必须被覆盖的方法的名称)他们raise NotImplementedError的基类! - )通常是单引导下划线名称,用于指示使用该类(或子类)的实例的代码,该方法不应直接调用。

例如,要创建一个具有与 FIFO 不同的排队规则的线程安全队列,可以导入 Queue,子类 Queue.Queue,并覆盖诸如_get_put类的方法; “客户端代码” 从不调用那些(“hook”)方法,而是调用(“组织”)公共方法,例如putget (这被称为模板方法设计模式 - 请参阅此处以获取基于的有趣演示文稿)关于这个主题的一个关于我的谈话的视频,增加了成绩单的概要)。

__foo__ :这只是一种约定,是 Python 系统使用不会与用户名冲突的名称的一种方式。

_foo :这只是一种约定,是程序员指示变量是私有的一种方式(无论在 Python 中是什么意思)。

__foo :这有实际意义:解释器用_classname__foo替换此名称,以确保名称不会与另一个类中的类似名称重叠。

没有其他形式的下划线在 Python 世界中有意义。

这些约定中的类,变量,全局等没有区别。