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


当前回答

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

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

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

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

其他回答

既然这么多人都在提到雷蒙德的谈话,我就把他说的话写下来,让事情变得简单一点:

双下划线的用意不是关于隐私。我们的意图是这样使用它类圆(对象):def__init__(自身,半径):self.radius=半径定义区域(自身):p=自身__周长()r=p/math.pi/2.0返回math.pi*r**2.0定义周长(自身):return 2.0*math.pi*self.radius__周界=周界#本地参考等级轮胎(圆形):定义周长(自身):返回圆周长(自身)*1.25这实际上是隐私的反面,都是关于自由的。它使您的子类可以自由覆盖任何一个方法,而不破坏其他方法。

假设您没有在Circle中保留周界的本地参考。现在,派生类Tire覆盖了周长的实现,而不接触面积。当您调用Tire(5).area()时,理论上它应该仍然使用Circle.perimeter进行计算,但实际上它使用的是Tire.perimet,这不是预期的行为。这就是为什么我们需要Circle的本地参考。

但为什么用周长代替周长?因为_perimeter仍然给派生类重写的机会:

class Tire(Circle):

    def perimeter(self):
        return Circle.perimeter(self) * 1.25

    _perimeter = perimeter

双下划线具有名称损坏,因此父类中的本地引用在派生类中被重写的可能性很小。因此“使您的子类可以自由覆盖任何一个方法而不破坏其他方法”。

如果您的类不会被继承,或者方法重写不会破坏任何东西,那么您就不需要__double_leading_underscore。

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

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

_foo:只是惯例。程序员指示变量是私有的(无论在Python中意味着什么)。__foo:这有真正的意义。解释器将此名称替换为_classname__foo,以确保该名称不会与其他类中的类似名称重叠。__foo__:只是惯例。Python系统使用不会与用户名冲突的名称的方法。

在Python世界中,没有其他形式的下划线有意义。此外,在这些约定中,类、变量、全局等之间没有区别。

单一前导下划线是一种惯例。如果名称是否以单个下划线开头,则从解释器的角度来看没有区别。

双前导和尾随下划线用于内置方法,如__init__、__bool__等。

双前导下划线不带尾随对应符也是一种惯例,但是,类方法将被解释器破坏。对于变量或基本函数名不存在差异。

为了用简单的语言来描述它,让我们将python变量的可访问性约定与Java中的访问修饰符进行比较:

(Python)                                     =   (Java)
_single_underscore_variable                  =   Protected (Accessible to class and its subclasses)
__double_underscore_variable                 =   Private (Accessible to class itself only)
no_underscore_variable                       =   Public (Accessible anywhere)

参考:https://www.tutorialsteacher.com/python/public-private-protected-modifiers