Python前后带下划线的属性有什么区别

55 投票
1 回答
32091 浏览
提问于 2025-04-17 14:36

我想知道在Python中,这些有什么区别?

self._var1
self._var1_
self.__var1
self.__var1__

1 个回答

97

作为一个入门指南,你可能会觉得下面这段来自PEP 8 - Python 代码风格指南的引用很有帮助:

此外,以下使用前导或后缀下划线的特殊形式被认可(这些通常可以与任何命名规则结合使用):

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

single_trailing_underscore_:按照约定用于避免与 Python 关键字冲突,例如 Tkinter.Toplevel(master, class_='ClassName')

__double_leading_underscore:在命名类属性时,会触发名称改名(在类 FooBar 内部,__boo 变成 _FooBar__boo;见下文)。

__double_leading_and_trailing_underscore__:表示在用户控制的命名空间中存在的“魔法”对象或属性。例如 __init____import____file__。切勿自己发明这样的名称;只使用文档中已有的名称。

不过你提到的是类属性,所以我们来看看你的具体例子:

单前导下划线

在你的类中命名一个属性为 self._var1,这表示这个属性应该只被类内部(或者可能是子类)访问,用户不需要直接访问它,也不应该修改它。你应该在使用 privateprotected 字段的地方使用前导下划线,但要知道,Python 并不会强制限制访问——你需要信任使用你类的用户不会做傻事,并且如果他们真的很确定自己知道自己在做什么,并且这样做是合理的,他们可以选择访问(或修改)你的类的私有字段。

单前导和后缀下划线

self._var1_ 是我从未见过的。我认为这种命名风格在 Python 世界中没有任何约定的含义。

双前导下划线

这个命名方式实际上有语法上的意义。在你的类内部引用 self.__var1 会触发名称改名。在类外部,这个变量会显示为 self._YourClassName__var1 而不是 self.__var1。并不是每个人都会使用这个命名方式——我所在的地方就完全不使用——对于简单的类来说,这感觉像是比使用单前导下划线更荒谬和烦人的选择。

不过,这种命名方式存在是有理由的;如果你使用了很多继承,单前导下划线就无法向阅读你代码的人表明“私有”和“受保护”变量之间的区别——有些变量甚至不应该被子类访问,而有些变量子类可以访问,但外部世界不可以。因此,在这种情况下,使用单前导下划线表示“受保护”,而双下划线表示“私有”可能是一个有用的约定(而且名称改名会允许子类使用同名变量而不会造成冲突)。

双前导和后缀下划线

self.__var1__ 是你绝对不应该创建的,因为双前导和后缀下划线的命名风格仅用于 Python 定义的具有特殊含义的名称,比如 __init____eq__ 方法。你可以重写这些方法来改变类的行为(实际上,几乎所有类都会有程序员定义的 __init__),但你不应该像 self.__var1__ 这样自己发明名称。

撰写回答