对象名称前的单下划线和双下划线的含义是什么?
Python 中对象名称前的单下划线和双下划线代表什么?
What do single and double leading underscores before an object's name represent in Python?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(19)
单下划线
在类中,带有前导下划线的名称向其他程序员表明该属性或方法旨在在该类中使用。然而,隐私并没有以任何方式强制。
在模块中的函数中使用前导下划线表示不应从其他地方导入它。
来自 PEP-8 风格指南:
双下划线(名称修改)
来自 Python 文档:
以及来自同一页面的警告:
示例
Single Underscore
In a class, names with a leading underscore indicate to other programmers that the attribute or method is intended to be be used inside that class. However, privacy is not enforced in any way.
Using leading underscores for functions in a module indicates it should not be imported from somewhere else.
From the PEP-8 style guide:
Double Underscore (Name Mangling)
From the Python docs:
And a warning from the same page:
Example
_foo
:只是一个约定。程序员表明该变量是私有的(无论这在 Python 中意味着什么)。__foo
:这有实际意义。解释器将此名称替换为_classname__foo
,以确保该名称不会与另一个类中的类似名称重叠。__foo__
:只是一个约定。 Python系统使用不会与用户名冲突的名称的一种方式。在 Python 世界中,其他形式的下划线都没有意义。此外,在这些约定中,类、变量、全局等之间没有区别。
_foo
: Only a convention. A way for the programmer to indicate that the variable is private (whatever that means in Python).__foo
: This has real meaning. The interpreter replaces this name with_classname__foo
as a way to ensure that the name will not overlap with a similar name in another class.__foo__
: Only a convention. A way for the Python system to use names that won't conflict with user names.No other form of underscores have meaning in the Python world. Also, there's no difference between class, variable, global, etc in these conventions.
到目前为止,答案很好,但缺少一些花絮。单个前导下划线并不完全只是一种约定:如果您使用
from foobar import *
,并且模块foobar
没有定义__all__
列表中,从模块导入的名称不包含以下划线开头的名称。假设这主要是一种约定,因为这个案例是一个相当不起眼的角落;-)。前导下划线约定不仅广泛用于私有名称,而且还用于 C++ 称为受保护的名称 - 例如,完全旨在被子类覆盖(即使是必须被覆盖的子类,因为在基类中它们
引发NotImplementedError
!-)通常是单前导下划线名称来指示代码<使用该类(或子类)的实例,该方法并不意味着直接调用。例如,要创建一个具有与 FIFO 不同的排队规则的线程安全队列,可以导入 Queue,子类化 Queue.Queue,并重写诸如
_get
和_put
之类的方法; “客户端代码”从不调用这些(“钩子”)方法,而是调用(“组织”)公共方法,例如put
和get
(这称为 < a href="http://en.wikipedia.org/wiki/Template_method_pattern" rel="noreferrer">模板方法设计模式 - 请参见 此处 提供了一个有趣的演示,该演示基于我关于该主题的演讲视频,并添加了抄本摘要)。编辑:演讲描述中的视频链接现已损坏。您可以在此处和此处。
Excellent answers so far but some tidbits are missing. A single leading underscore isn't exactly just a convention: if you use
from foobar import *
, and modulefoobar
does not define an__all__
list, the names imported from the module do not include those with a leading underscore. Let's say it's mostly a convention, since this case is a pretty obscure corner;-).The leading-underscore convention is widely used not just for private names, but also for what C++ would call protected ones -- for example, names of methods that are fully intended to be overridden by subclasses (even ones that have to be overridden since in the base class they
raise NotImplementedError
!-) are often single-leading-underscore names to indicate to code using instances of that class (or subclasses) that said methods are not meant to be called directly.For example, to make a thread-safe queue with a different queueing discipline than FIFO, one imports Queue, subclasses Queue.Queue, and overrides such methods as
_get
and_put
; "client code" never calls those ("hook") methods, but rather the ("organizing") public methods such asput
andget
(this is known as the Template Method design pattern -- see e.g. here for an interesting presentation based on a video of a talk of mine on the subject, with the addition of synopses of the transcript).Edit: The video links in the description of the talks are now broken. You can find the first two videos here and here.
._variable
是半私有的,仅用于约定.__variable
通常被错误地视为超私有,而其实际含义只是为了命名以防止意外访问 [1].__variable__
通常是为内置方法或变量保留如果您迫切需要,您仍然可以访问
.__mangled
变量。双下划线只是将变量命名或重命名为instance._className__mangled
示例:
t._b 是可访问的,因为它只是按照约定隐藏
t.__a 找不到,因为它不再存在由于 namemangling
通过访问
instance._className__variable
而不仅仅是双下划线名称,您可以访问隐藏值._variable
is semiprivate and meant just for convention.__variable
is often incorrectly considered superprivate, while its actual meaning is just to namemangle to prevent accidental access[1].__variable__
is typically reserved for builtin methods or variablesYou can still access
.__mangled
variables if you desperately want to. The double underscores just namemangles, or renames, the variable to something likeinstance._className__mangled
Example:
t._b is accessible because it is only hidden by convention
t.__a isn't found because it no longer exists due to namemangling
By accessing
instance._className__variable
instead of just the double underscore name, you can access the hidden value开头单下划线:
Python 没有真正的私有方法。相反,方法或属性名称开头的一个下划线意味着您不应访问此方法,因为它不是 API 的一部分。
(此代码片段取自 Django 源代码:django/forms/forms.py)。在此代码中,
errors
是公共属性,但该属性调用的方法 _get_errors 是“私有”的,因此您不应访问它。开头有两个下划线:
这会引起很多混乱。它不应该用于创建私有方法。它应该用于避免您的方法被子类覆盖或意外访问。让我们看一个例子:
输出:
现在创建一个子类 B 并为 __test 方法进行定制
输出将是...
正如我们所见,B.test() 没有像我们预期的那样调用 B.__test() 方法。但事实上,这是 __ 的正确行为。名为 __test() 的两个方法会自动重命名(损坏)为 _A__test() 和 _B__test(),因此它们不会意外覆盖。当您创建以 __ 开头的方法时,这意味着您不希望任何人能够覆盖它,并且您只想从它自己的类内部访问它。
开头和结尾各有两个下划线:
当我们看到像
__this__
这样的方法时,不要调用它。这是 Python 应该调用的方法,而不是您。让我们看一下:总有一个运算符或本机函数调用这些魔术方法。有时它只是特定情况下 Python 调用的一个钩子。例如,在调用
__new__()
构建实例之后创建对象时,会调用__init__()
...让我们举个例子...
有关更多详细信息,请参阅 PEP-8 指南 。有关更多魔术方法,请参阅此 PDF。
Single underscore at the beginning:
Python doesn't have real private methods. Instead, one underscore at the start of a method or attribute name means you shouldn't access this method, because it's not part of the API.
(This code snippet was taken from Django source code: django/forms/forms.py). In this code,
errors
is a public property, but the method this property calls, _get_errors, is "private", so you shouldn't access it.Two underscores at the beginning:
This causes a lot of confusion. It should not be used to create a private method. It should be used to avoid your method being overridden by a subclass or accessed accidentally. Let's see an example:
Output:
Now create a subclass B and do customization for __test method
The output will be...
As we have seen, B.test() didn't call B.__test() methods, as we might expect. But in fact, this is the correct behavior for __. The two methods called __test() are automatically renamed (mangled) to _A__test() and _B__test(), so they do not accidentally override. When you create a method starting with __ it means that you don't want anyone to be able to override it, and you only intend to access it from inside its own class.
Two underscores at the beginning and at the end:
When we see a method like
__this__
, don't call it. This is a method which Python is meant to call, not you. Let's take a look:There is always an operator or native function which calls these magic methods. Sometimes it's just a hook Python calls in specific situations. For example
__init__()
is called when the object is created after__new__()
is called to build the instance...Let's take an example...
For more details, see the PEP-8 guide. For more magic methods, see this PDF.
根据 Python 中下划线的含义
var_
):按惯例使用以避免与Python关键字发生命名冲突。__var
):在类上下文中使用时触发名称修改。由 Python 解释器强制执行。__var__
):表示Python语言定义的特殊方法。避免为您自己的属性采用这种命名方案。_
):有时用作临时或无关紧要的变量的名称(“不关心”)。另外:Python REPL 中最后一个表达式的结果。According to Meaning of Underscores in Python
_var
): Naming convention indicating a name is meant for internal use. Generally not enforced by the Python interpreter (except in wildcard imports) and meant as a hint to the programmer only.var_
): Used by convention to avoid naming conflicts with Python keywords.__var
): Triggers name mangling when used in a class context. Enforced by the Python interpreter.__var__
): Indicates special methods defined by the Python language. Avoid this naming scheme for your own attributes._
): Sometimes used as a name for temporary or insignificant variables (“don’t care”). Also: The result of the last expression in a Python REPL.由于很多人都在参考 Raymond 的演讲,我就简单说一下写下他说的话会更容易一些:
假设您没有在
Circle
中保留perimeter
的本地引用。现在,派生类Tire
重写了perimeter
的实现,而不触及area
。当您调用Tire(5).area()
时,理论上它应该仍然使用Circle.perimeter
进行计算,但实际上它使用Tire.perimeter
,这不是预期的行为。这就是为什么我们需要 Circle 中的本地引用。但为什么是
__perimeter
而不是_perimeter
呢?因为_perimeter
仍然为派生类提供了重写的机会:双下划线具有名称修改,因此父类中的本地引用在派生类中被重写的机会很小。因此“使您的子类可以自由地重写任何一种方法,而不会破坏其他方法”。
如果您的类不会被继承,或者方法重写不会破坏任何内容,那么您根本不需要
__double_leading_underscore
。Since so many people are referring to Raymond's talk, I'll just make it a little easier by writing down what he said:
Say you don't keep a local reference of
perimeter
inCircle
. Now, a derived classTire
overrides the implementation ofperimeter
, without touchingarea
. When you callTire(5).area()
, in theory it should still be usingCircle.perimeter
for computation, but in reality it's usingTire.perimeter
, which is not the intended behavior. That's why we need a local reference in Circle.But why
__perimeter
instead of_perimeter
? Because_perimeter
still gives derived class the chance to override:Double underscores has name mangling, so there's a very little chance that the local reference in parent class get override in derived class. thus "makes your subclasses free to override any one method without breaking the others".
If your class won't be inherited, or method overriding does not break anything, then you simply don't need
__double_leading_underscore
.有时您会看到一个带有前导下划线的元组,如在
本例中,发生的情况是 _() 是本地化函数的别名,该函数对文本进行操作以将其转换为正确的语言等。语言环境。例如,Sphinx 就是这样做的,您会发现在导入
和 sphinx.locale 中,_() 被指定为某些本地化函数的别名。
Sometimes you have what appears to be a tuple with a leading underscore as in
In this case, what's going on is that _() is an alias for a localization function that operates on text to put it into the proper language, etc. based on the locale. For example, Sphinx does this, and you'll find among the imports
and in sphinx.locale, _() is assigned as an alias of some localization function.
_var
:Python 中以单下划线开头的变量是经典变量,旨在通知其他使用您代码的人该变量应保留供内部使用。它们与经典变量有一点不同:在定义它们的对象/模块中进行通配符导入时,不会导入它们(定义__all__
变量)。例如:_
:单下划线是前导单下划线变量的特殊情况。按照惯例,它被用作垃圾变量,用于存储以后不打算访问的值。它也不是通过通配符导入来导入的。例如:这个for
循环打印“我不能在课堂上讲话”10 次,并且永远不需要访问_
变量。var_
:单个尾随下划线变量。它们是按惯例使用的经典变量,以避免与 Python 关键字冲突。例如:__var
:双前导下划线变量(至少两个前导下划线,最多一个尾随下划线)。当用作类属性(变量和方法)时,这些变量会受到名称修改的影响:在类之外,Python 会将属性重命名为___
。示例:当在类外部用作变量时,它们的行为类似于单个前导下划线变量。
__var__
:双前导和尾随下划线变量(至少两个前导和尾随下划线)。也称为dunders。 python 使用此命名约定在内部定义变量。避免使用此约定来防止 python 更新可能出现的名称冲突。 Dunder 变量的行为类似于单个前导下划线变量:它们在类内部使用时不受名称修改的影响,但不会在通配符导入中导入。_var
: variables with a leading single underscore in python are classic variables, intended to inform others using your code that this variable should be reserved for internal use. They differ on one point from classic variables: they are not imported when doing a wildcard import of an object/module where they are defined (exceptions when defining the__all__
variable). Eg:_
: the single underscore is a special case of the leading single underscore variables. It is used by convention as a trash variable, to store a value that is not intended to be later accessed. It is also not imported by wildcard imports. Eg: thisfor
loop prints "I must not talk in class" 10 times, and never needs to access the_
variable.var_
: single trailing underscore variables. They are classic variables used by convention to avoid conflicts with Python keyword. Eg:__var
: double leading underscore variables (at least two leading underscores, at most one trailing underscore). When used as class attributes (variables and methods), these variables are subject to name mangling: outside of the class, python will rename the attribute to_<Class_name>__<attribute_name>
. Example:When used as variables outside a class, they behave like single leading underscore variables.
__var__
: double leading and trailing underscore variables (at least two leading and trailing underscores). Also called dunders. This naming convention is used by python to define variables internally. Avoid using this convention to prevent name conflicts that could arise with python updates. Dunder variables behave like single leading underscore variables: they are not subject to name mangling when used inside classes, but are not imported in wildcard imports.如果确实想将变量设置为只读,恕我直言,最好的方法是使用 property() ,仅将 getter 传递给它。使用 property() 我们可以完全控制数据。
我知道OP问了一个不同的问题,但由于我发现另一个问题询问“如何设置私有变量”,与这个问题标记重复,我想在这里添加这个附加信息。
If one really wants to make a variable read-only, IMHO the best way would be to use property() with only getter passed to it. With property() we can have complete control over the data.
I understand that OP asked a little different question but since I found another question asking for 'how to set private variables' marked duplicate with this one, I thought of adding this additional info here.
很好的答案,而且都是正确的。我提供了简单的示例以及简单的定义/含义。
含义:
some_variable --► 它是公开的,任何人都可以看到它。
_some_variable --► 它是公开的,任何人都可以看到它,但这是表示私有的约定...警告Python 不执行任何强制操作。
__some_varaible --► Python 用 _classname__some_varaible 替换变量名(又名名称修改),它减少/隐藏它的可见性,并且更像私有变量。
老实说根据Python文档
示例:
Great answers and all are correct.I have provided simple example along with simple definition/meaning.
Meaning:
some_variable --► it's public anyone can see this.
_some_variable --► it's public anyone can see this but it's a convention to indicate private...warning no enforcement is done by Python.
__some_varaible --► Python replaces the variable name with _classname__some_varaible (AKA name mangling) and it reduces/hides it's visibility and be more like private variable.
Just to be honest here According to Python documentation
The example:
下面是一个简单的说明性示例,说明双下划线属性如何影响继承的类。因此,通过以下设置:
如果您随后在 python REPL 中创建一个子实例,您将看到下面的内容
这对某些人来说可能是显而易见的,但在更复杂的环境中它让我措手不及
Here is a simple illustrative example on how double underscore properties can affect an inherited class. So with the following setup:
if you then create a child instance in the python REPL, you will see the below
This may be obvious to some, but it caught me off guard in a much more complex environment
单前导下划线是一种约定。从解释器的角度来看,名称是否以下划线开头没有区别。
双前导和尾随下划线用于内置方法,例如
__init__
、__bool__
等。双前导下划线不带尾随对应项也是一种约定,但是,类方法将被解释器mangled。对于变量或基本函数名称不存在差异。
Single leading underscores is a convention. there is no difference from the interpreter's point of view if whether names starts with a single underscore or not.
Double leading and trailing underscores are used for built-in methods, such as
__init__
,__bool__
, etc.Double leading underscores w/o trailing counterparts are a convention too, however, the class methods will be mangled by the interpreter. For variables or basic function names no difference exists.
你的问题问得好,不仅仅是方法问题。模块中的函数和对象通常也以一个下划线为前缀,并且可以以两个下划线为前缀。
但是,例如,__double_underscore 名称在模块中不会被名称破坏。发生的情况是,如果从模块导入所有名称(from module import *),则不会导入以一个(或多个)下划线开头的名称,help(module) 中也不会显示名称。
Your question is good, it is not only about methods. Functions and objects in modules are commonly prefixed with one underscore as well, and can be prefixed by two.
But __double_underscore names are not name-mangled in modules, for example. What happens is that names beginning with one (or more) underscores are not imported if you import all from a module (from module import *), nor are the names shown in help(module).
Python 中不存在除了从对象内部之外无法访问的“私有”实例变量。然而,大多数 Python 代码都遵循一个约定:以下划线前缀的名称(例如 _spam)应被视为 API 的非公共部分(无论是函数、方法还是数据成员) 。它应被视为实施细节,如有更改,恕不另行通知。
参考
https://docs.python.org /2/tutorial/classes.html#private-variables-and-class-local-references
“Private” instance variables that cannot be accessed except from inside an object don’t exist in Python. However, there is a convention that is followed by most Python code: a name prefixed with an underscore (e.g. _spam) should be treated as a non-public part of the API (whether it is a function, a method or a data member). It should be considered an implementation detail and subject to change without notice.
reference
https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references
获取 _ 和 __ 的事实非常容易;其他答案很好地表达了它们。其用途更难确定。
我是这样看的:
应该用来表明某个函数不供公共使用,例如 API。这个和导入限制使它的行为与 C# 中的
internal
非常相似。应该用于避免继承层次结构中的名称冲突并避免后期绑定。很像 c# 中的 private。
==>
如果您想表明某些内容不供公共使用,但其行为应类似于
protected
,请使用_
。如果您想表明某些内容不供公共使用,但其行为应类似于
private
,请使用__
。这也是我非常喜欢的一句话:
但我认为,这样做的问题是,如果没有 IDE 在您重写方法时发出警告,那么如果您不小心重写了基类中的方法,则可能需要一段时间才能找到错误。
Getting the facts of _ and __ is pretty easy; the other answers express them pretty well. The usage is much harder to determine.
This is how I see it:
Should be used to indicate that a function is not for public use as for example an API. This and the import restriction make it behave much like
internal
in c#.Should be used to avoid name collision in the inheritace hirarchy and to avoid latebinding. Much like private in c#.
==>
If you want to indicate that something is not for public use, but it should act like
protected
use_
.If you want to indicate that something is not for public use, but it should act like
private
use__
.This is also a quote that I like very much:
But the problem with that is in my opinion that if there's no IDE that warns you when you override methods, finding the error might take you a while if you have accidentially overriden a method from a base-class.
对于方法,您可以使用双下划线通过以下模式隐藏私有“方法”:
输出:
今天,当我尝试对类方法使用双下划线并得到
NameError: name ' 时,我偶然发现了这一点_<类><方法>'未定义错误。
In the case of methods, you can use the double underscore to hide away private 'methods' with the following pattern:
Output:
I stumbled across this today when I tried using double underscore for class methods and got the
NameError: name '_<class><method>' is not defined
error.为了用简单的话来表达它,让我们将 python 变量的可访问性约定与 Java 中的访问修饰符进行比较:
参考:https://www.tutorialsteacher.com/python/public-private-protected-modifiers
To frame it in simple words, let us compare python's variables' accessibility conventions to access modifiers in Java:
Reference: https://www.tutorialsteacher.com/python/public-private-protected-modifiers
_obj 表示受保护(可以在定义类及其子类内访问)
--obj 表示私有(它们不能从定义它们的类外部直接访问。但是,Python 并不像其他一些语言那样强制执行严格的私有访问;相反,它执行名称重整,使访问变得更加困难,但并非不可能。)
重整是 Python 中的一项功能,它修改类成员的名称,以使其更难从类外部直接访问。这是一种用于创建“伪私有”变量和方法的技术。这是通过在成员名称前加上双下划线 (__) 前缀但不以另一个双下划线结尾来完成的
_obj means protected (can be accessed within the defining class and its subclasses)
--obj means private (They are not directly accessible from outside the class where they are defined. However, Python does not enforce strict private access like some other languages do; instead, it performs name mangling to make access more difficult but not impossible.)
Mangling is a feature in Python that modifies the name of a class member to make it harder to access directly from outside the class. It's a technique used to create "pseudo-private" variables and methods. This is done by prefixing the member name with a double underscore (__) but not ending with another double underscore