Home > Backend Development > Python Tutorial > What are the meanings and uses of underscores in Python?

What are the meanings and uses of underscores in Python?

WBOY
Release: 2023-04-20 20:04:14
forward
1556 people have browsed it

1. Single leading underscore: _var

When it comes to variable and method names, the single underscore prefix has a conventional meaning. It is a reminder to programmers - meaning that the Python community agrees on what it should mean, but the behavior of the program is not affected.

The meaning of the underscore prefix is ​​to inform other programmers that variables or methods starting with a single underscore are for internal use only. This convention is defined in PEP 8.

This is not mandated by Python. Python doesn't have a strong distinction between "private" and "public" variables like Java does. It's like someone put up a little underline warning sign saying: "Hey, this isn't really meant to be part of the class's public interface. Just leave it alone."

##2. Single trailing underscore var_

Sometimes, the most appropriate name for a variable is already occupied by a keyword. Therefore, names like class or def cannot be used as variable names in Python. In this case, you can resolve the naming conflict by appending an underscore:
>>> def make_object(name, class):
SyntaxError: "invalid syntax"

>>> def make_object(name, class_):
...    pass
Copy after login

In short, a single trailing underscore (suffix) is a convention to avoid naming conflicts with Python keywords. PEP 8 explains this convention.

3. Double leading underscore __var

The meanings of all the naming patterns we have covered so far come from agreed-upon conventions. For Python class attributes (including variables and methods) that begin with a double underscore, the situation is a bit different.

The double underscore prefix causes the Python interpreter to rewrite the property name to avoid naming conflicts in subclasses.

This is also called name mangling - the interpreter changes the name of the variable so that it is less likely to conflict when the class is extended.

I know this sounds abstract. Therefore, I put together a small code example to illustrate:

class Test:
   def __init__(self):
       self.foo = 11
       self._bar = 23
       self.__baz = 23
Copy after login

Let's use the built-in dir() function to take a look at the properties of this object:

>>> t = Test()
>>> dir(t)
['_Test__baz', '__class__', '__delattr__', '__dict__', '__dir__',
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
'__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__',
'__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__sizeof__', '__str__', '__subclasshook__',
'__weakref__', '_bar', 'foo']
Copy after login

The above is the object List of properties. Let's take a look at this list and look for our original variable names

foo, _bar

and

__baz

- I guarantee you'll notice some interesting changes. The self.foo variable appears unmodified as foo in the property list. self._bar behaves the same way - it appears on the class as _bar. Like I said before, the leading underscore is just a convention in this case. Just a hint for programmers. However, for

self.__baz

, things look a little different. When you search for __baz in this list, you will not see a variable with this name. __What happened to baz?

If you look closely, you will see that there is a property called _Test__baz on this object. This is name mangling done by the Python interpreter. It does this to prevent variables from being overridden in subclasses.

Let's create another class that extends the Test class and try to override the existing properties added in the constructor: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">class ExtendedTest(Test): def __init__(self): super().__init__() self.foo = &amp;#39;overridden&amp;#39; self._bar = &amp;#39;overridden&amp;#39; self.__baz = &amp;#39;overridden&amp;#39;</pre><div class="contentsignin">Copy after login</div></div> Now, you think foo,

_bar

Will the values ​​​​and

__baz

appear on this instance of the ExtendedTest class? Let's take a look: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">&gt;&gt;&gt; t2 = ExtendedTest() &gt;&gt;&gt; t2.foo &amp;#39;overridden&amp;#39; &gt;&gt;&gt; t2._bar &amp;#39;overridden&amp;#39; &gt;&gt;&gt; t2.__baz AttributeError: &quot;&amp;#39;ExtendedTest&amp;#39; object has no attribute &amp;#39;__baz&amp;#39;&quot;</pre><div class="contentsignin">Copy after login</div></div>Wait a minute, why do we get an AttributeError when we try to view the value of t2.__ baz? Name modification is triggered again! It turns out that this object doesn't even have the

__baz

attribute: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">&gt;&gt;&gt; dir(t2) [&amp;#39;_ExtendedTest__baz&amp;#39;, &amp;#39;_Test__baz&amp;#39;, &amp;#39;__class__&amp;#39;, &amp;#39;__delattr__&amp;#39;, &amp;#39;__dict__&amp;#39;, &amp;#39;__dir__&amp;#39;, &amp;#39;__doc__&amp;#39;, &amp;#39;__eq__&amp;#39;, &amp;#39;__format__&amp;#39;, &amp;#39;__ge__&amp;#39;, &amp;#39;__getattribute__&amp;#39;, &amp;#39;__gt__&amp;#39;, &amp;#39;__hash__&amp;#39;, &amp;#39;__init__&amp;#39;, &amp;#39;__le__&amp;#39;, &amp;#39;__lt__&amp;#39;, &amp;#39;__module__&amp;#39;, &amp;#39;__ne__&amp;#39;, &amp;#39;__new__&amp;#39;, &amp;#39;__reduce__&amp;#39;, &amp;#39;__reduce_ex__&amp;#39;, &amp;#39;__repr__&amp;#39;, &amp;#39;__setattr__&amp;#39;, &amp;#39;__sizeof__&amp;#39;, &amp;#39;__str__&amp;#39;, &amp;#39;__subclasshook__&amp;#39;, &amp;#39;__weakref__&amp;#39;, &amp;#39;_bar&amp;#39;, &amp;#39;foo&amp;#39;, &amp;#39;get_vars&amp;#39;]</pre><div class="contentsignin">Copy after login</div></div> As you can see __baz becomes

_ExtendedTest__baz

to prevent accidental modification: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">&gt;&gt;&gt; t2._ExtendedTest__baz &amp;#39;overridden&amp;#39;</pre><div class="contentsignin">Copy after login</div></div>But the original _Test__baz is still there:

>>> t2._Test__baz
42
Copy after login

Double underscore name modification is completely transparent to programmers. The following example confirms this: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">class ManglingTest: def __init__(self): self.__mangled = &amp;#39;hello&amp;#39; def get_mangled(self): return self.__mangled &gt;&gt;&gt; ManglingTest().get_mangled() &amp;#39;hello&amp;#39; &gt;&gt;&gt; ManglingTest().__mangled AttributeError: &quot;&amp;#39;ManglingTest&amp;#39; object has no attribute &amp;#39;__mangled&amp;#39;&quot;</pre><div class="contentsignin">Copy after login</div></div>Does name decoration also apply to method names? Yes, that applies too. Name decoration affects all names that begin with the two underscore characters

("dunders")

in the context of a class:

class MangledMethod:
   def __method(self):
       return 42

   def call_it(self):
       return self.__method()

>>> MangledMethod().__method()
AttributeError: "&#39;MangledMethod&#39; object has no attribute &#39;__method&#39;"
>>> MangledMethod().call_it()
42
Copy after login

This is another, perhaps surprising, use of names Modified example: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">_MangledGlobal__mangled = 23 class MangledGlobal: def test(self): return __mangled &gt;&gt;&gt; MangledGlobal().test() 23</pre><div class="contentsignin">Copy after login</div></div> In this example, I declare a global variable named

_MangledGlobal__mangled

. Then I access the variable in the context of a class called MangledGlobal. Because of the name modification, I can reference the

_MangledGlobal__mangled

global variable as __mangled within the test() method of the class. The Python interpreter automatically expands the name __mangled to

_MangledGlobal__mangled

because it begins with two underscore characters. This indicates that name decoration is not specifically associated with class attributes. It works for any name starting with two underscore characters used in a class context. There is a lot to absorb. Honestly, these examples and explanations didn’t come out of my head. It took me some research and processing to come up with it. I've always used Python, and have for many years, but rules and special cases like this don't always come to mind.

Sometimes the most important skill for a programmer is "pattern recognition" and knowing where to look for information. If you're feeling a little overwhelmed at this point, don't worry. Take your time and try some of the examples in this article.

让这些概念完全沉浸下来,以便你能够理解名称修饰的总体思路,以及我向您展示的一些其他的行为。如果有一天你和它们不期而遇,你会知道在文档中按什么来查。

4.双前导和双末尾下划线 _var_

也许令人惊讶的是,如果一个名字同时以双下划线开始和结束,则不会应用名称修饰。 由双下划线前缀和后缀包围的变量不会被Python解释器修改:

class PrefixPostfixTest:
   def __init__(self):
       self.__bam__ = 42

>>> PrefixPostfixTest().__bam__
42
Copy after login

但是,Python保留了有双前导和双末尾下划线的名称,用于特殊用途。 这样的例子有,__init__对象构造函数,或__call__ — 它使得一个对象可以被调用。

这些dunder方法通常被称为神奇方法 - 但Python社区中的许多人(包括我自己)都不喜欢这种方法。

最好避免在自己的程序中使用以双下划线(“dunders”)开头和结尾的名称,以避免与将来Python语言的变化产生冲突。

5.单下划线 _

按照习惯,有时候单个独立下划线是用作一个名字,来表示某个变量是临时的或无关紧要的。

例如,在下面的循环中,我们不需要访问正在运行的索引,我们可以使用“_”来表示它只是一个临时值:

>>> for _ in range(32):
...    print(&#39;Hello, World.&#39;)
Copy after login

你也可以在拆分(unpacking)表达式中将单个下划线用作“不关心的”变量,以忽略特定的值。 同样,这个含义只是“依照约定”,并不会在Python解释器中触发特殊的行为。 单个下划线仅仅是一个有效的变量名称,会有这个用途而已。

在下面的代码示例中,我将汽车元组拆分为单独的变量,但我只对颜色和里程值感兴趣。 但是,为了使拆分表达式成功运行,我需要将包含在元组中的所有值分配给变量。 在这种情况下,“_”作为占位符变量可以派上用场:

>>> car = (&#39;red&#39;, &#39;auto&#39;, 12, 3812.4)
>>> color, _, _, mileage = car

>>> color
&#39;red&#39;
>>> mileage
3812.4
>>> _
12
Copy after login

除了用作临时变量之外,“_”是大多数Python REPL中的一个特殊变量,它表示由解释器评估的最近一个表达式的结果。

这样就很方便了,比如你可以在一个解释器会话中访问先前计算的结果,或者,你是在动态构建多个对象并与它们交互,无需事先给这些对象分配名字:

>>> 20 + 3
23
>>> _
23
>>> print(_)
23

>>> list()
[]
>>> _.append(1)
>>> _.append(2)
>>> _.append(3)
>>> _
[1, 2, 3]
Copy after login

The above is the detailed content of What are the meanings and uses of underscores in Python?. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:yisu.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template