Python中的下划线_有多少个意思?

比如: _var__var_var_
关注者
50
被浏览
23,220

11 个回答

大概有10种。

如下:

# No.1
# 在交互式解释器中获取上一个语句执行的结果
# 比如:
# >>> 1+1
# 2
# >>> _
# 2
# >>> _ * 5
# 10
_

# No.2
# 用来在函数、模块、包、变量名中分隔单词,增加可读性
var_foo_bar

# No.3
# 内部使用的变量、属性、方法、函数、类或模块(约定)
# from foo import * 不会导入以下划线开头的对象
_var

# No.4
# 避免和保留的关键字冲突(约定)
# 比如:class_、type_
var_

# No.5
# 在类内的私有变量(private)
# 类外部无法直接使用原名称访问
# 需要通过instance._ClassName__var的形式访问(name mangling)
__var

# No.6(这一条存疑)
# 在类内的保护变量
_var_

# No.7
# Python内置的“魔法”方法或属性
# 你也可以自己定义,但一般不推荐
# 比如:__init__, __file__, __main__
__var__

# No.8
# 作为内部使用的一次性变量
# 通常在循环里使用
# 比如:[_ for _ in range(10)]
# 或是用作占位,不实际使用的变量
# 比如:for _, a in [(1,2),(3,4)]: print a
_

# No.9
# i18n里作为gettext()的缩写
_()

# No.10
# 用来分隔数值以增加可读性(Python 3.6新增)
# 比如
# >>> num = 1_000_000 
# >>> num
# 1000000
1_000_000

参考链接:

1. 概述

在Python经常能见到含下划线(underscore)修饰的的变量和方法(如__name__,_var等),这些下划线的作用称之为名字修饰(name decoration)。在Python中,名字修饰通常有以下几种情况:

  • 单前缀下划线(single leading underscore):_var
  • 单后缀下划线(single trailingunderscore):var_
  • 双前缀下划线(double leading underscores):__var
  • 双前缀+双后缀下划线(double leading & trailing underscores):__var__

除了名字修饰,在Python中下划线还有以下用法:

  • 单独一个下划线
  • 数字分隔符下划线
  • IPython中的特殊用途

我们对以上用法进行逐一详解。

2. 名字修饰(name decoration)

2.1 单前缀下划线

方法和实例变量

Use one leading underscore only for non-public methods and instance variables.[1]

即,单前缀下划线用于私有的方法和实例变量。但Python和Java不同,并没有对公有和私有进行严格的区分。即便一个方法或者变量有单前缀下划线,也不影响被外界调用,它的作用仅限于一种“提示”(weak “internal use” indicator)。

class Test:

    def __init__(self):
        self.a = "a"
        self._b = "b"

    def _private_method(self):
        return ("This is a private method!")

# 单前缀下划线并不影响从外界调用
t = Test()
print(t.a)
print(t._b)
print(t._private_method)

导入

from M import *does not import objects whose names start with an underscore.[1]

即,当从另一个模块导入内容是,含前缀下划线的内容不会被导入。如

# demo.py
a = "a"
_b = "b"

def _private_function():
    return "This is a private function!"


from demo import *

print(a)
print(_b)                   # 会报错,私有变量无法导入
print(_private_function)    # 会报错,私有函数无法导入

2.2 单后缀下划线

single_trailing_underscore_: used by convention to avoid conflicts with Python keyword[1]

单后缀下划线主要是为了避免与一些Python关键字(如class,sum之类的)的冲突,如

tkinter.Toplevel(master, class_='ClassName')

2.3 双前缀下划线

To avoid name clashes with subclasses, use two leading underscores to invoke Python's name mangling rules.
Python mangles these names with the class name: if class Foo has an attribute named __a, it cannot be accessed by Foo.__a. (An insistent user could still gain access by calling Foo._Foo__a.) Generally, double leading underscores should be used only to avoid name conflicts with attributes in classes designed to be subclassed.[1]

双前缀下划线会触发Python中的名字改写规则(name mangling)什么意思呢?举个例子

class Test:
    __a = "__a"

    def __init__(self) -> None:
        self.__b = "__b"
        self._c = "_c"
        self.d = "d"

t = Test()
print(dir(t))

猜猜会打印什么呢?结果如下

name mangling

你会发现有_c和d,但是没有__a和__b。这是为什么呢?这是因为他们被改写成了_Test__a和_Test_b。因为名字被改写,所以不能通过t.__a访问,但是可以通过t._Test__a进行访问。

print(t.__a)        # 会报错
print(t._Test__a)   # 不会报错

为什么要这样设计呢?这样是为了避免在继承的时候,这些变量被重写,如

class Test:
    __a = "__a"

class SubTest(Test):
    __a = "change __a"

st = SubTest()
print(dir(st))

执行结果如下,如果在子类中重新定义__a时,会重新生成一个_SubTest__a,这样避免了父类中的_Test__a被改写。

除了_Test__a,还有_SubTest__a

2.4 双前缀+双后缀下划线

与双前缀下划线不同,双前缀+双后缀下划线并不会对名字进行改写。这些使用了双前缀+双后缀下划线的对象又被称为dunders,即Double UNDERScores的缩写。

魔法函数

__double_leading_and_trailing_underscore__: “magic” objects or attributes that live in user-controlled namespaces. E.g. __init__, __import__ or __file__. Never invent such names; only use them as documented.

双前缀+双后缀下划线常用于“魔法函数”,表明这些函数被“官方占用”,不建议自行定义一个双前缀+双后缀下划线的对象,因为有可能与“官方用法”产生冲突。

模块

Module level “dunders” (i.e. names with two leading and two trailing underscores) such as__all__,__author__,__version__, etc. should be placed after the module docstring but before any import statements exceptfrom__future__imports. Python mandates that future-imports must appear in the module before any other code except docstrings:

除了魔法函数,一些模块也使用了双前缀+双后缀下划线,如__future__。Python要求的导入顺序是:__future__的import放在最前,然后是dunders的import,最后是普通的import。其中__future__的import强制放在最前,否则会报错。

"""
This is a demo! 这种docstrings放在最前
"""

from __future__ import barry_as_FLUFL

__all__ = ["test"]
__version__ = '0.1'
__author__ = 'Mr. Cheng'

import pandas as pd

3. 其他用法

3.1 单独一个下划线

当我们需要一个变量,但是又不需要在后面的程序中调用这个变量时,就可以用_,相当于告诉大家:这个变量无关紧要。最典型的例子就是用于for循环,如

for _ in range(10):
    print("打印10次!")

也可以用作占位符对可迭代对象进行拆分,如

a, _, _, c = (1, 2, 3, 4)
a, _, _, c = [1, 2, 3, 4]

3.2 数字分隔符

在会计中,我们用逗号对较大的数字进行分隔,以方便识别,如93,123,110。但是在Python中,显然不能用逗号,但是可以用下划线,如:

a = 93_123_110

3.3 IPython中的特殊用途

在iPython中,下划线还有一个特殊用途:用以指代最近一个表达式的输出结果。如

IPython中的特殊用途

参考

  1. ^abcdPEP 8 https://peps.python.org/pep-0008/