在Python中,单下划线"_"变量的目的是什么?

787
在这段代码中,for后面的_是什么意思?
if tbh.bag:
    n = 0
    for _ in tbh.bag.atom_set():
        n += 1
5个回答

998

_ 在 Python 中有三个主要的常规用途:

  1. 在交互式解释器会话中保存上次执行表达式的结果(请参见docs)。这个先例是由标准的CPython解释器设定的,其他解释器也遵循了这个先例。

  2. 用于i18n翻译查找(例如,请参阅gettext文档),如以下代码:

    raise forms.ValidationError(_("Please enter a correct username"))
    
  3. 作为通用的“丢弃”变量名称:

    1. 表示函数结果的一部分被故意忽略(从概念上讲,它被丢弃了),例如以下代码:

      label, has_label, _ = text.partition(':')
      
    2. 作为函数定义的一部分(使用deflambda),其中签名是固定的(例如通过回调或父类API),但是此特定函数实现不需要所有参数,例如以下代码:

      def callback(_):
          return True
      

      [长时间以来,这个答案没有列出这种用法,但是它经常出现,如here所述,值得明确列出。]

    这种用法可能与翻译查找用例冲突,因此需要避免在任何代码块中使用_作为丢弃变量,该代码块还使用它进行i18n翻译(许多人喜欢使用双下划线__作为丢弃变量,正是出于这个原因)。

    Linters通常会识别这种用法。例如,year, month, day = date()将在代码后面没有使用day时引发lint警告。如果确实不需要day,则修复方法是编写year, month, _ = date()。lambda函数也是如此,lambda arg: 1.0创建一个需要一个参数但不使用它的函数,这将被lint捕获。修复方法是编写lambda _: 1.0。未使用的变量通常隐藏着错误/拼写错误(例如,在下一行设置day但使用dya)。

    Python 3.10中添加的模式匹配功能将此用法从“约定”提升到“语言语法”,涉及到match语句:在匹配情况下,_是一个wildcard pattern,运行时甚至不会将值绑定到该符号。

    对于其他用例,请记住_仍然是一个有效的变量名称,因此仍将保留对象。在这种不希望的情况下(例如释放内存或外部资源),显式的del name调用既可以满足linters使用名称的要求,可以立即清除对对象的引用。


24
你能解释一下函数调用的工作原理吗?比如说:**raise forms.ValidationError(_("Please enter a correct username"))**。我在 Django 代码中看到过这个,但它并不清楚在做什么。 - John C
44
这是用法2- 按照惯例,“_”是用于执行国际化和本地化字符串翻译查找的函数的名称。我相当确定是C语言的“gettext”库确立了这个惯例。 - ncoghlan
50
就我个人而言,为了避免与前两种用例发生冲突,我已经开始使用“__”(双下划线)作为通用的临时变量。 - ncoghlan
17
新兴社区惯例通常没有权威来源——只是随着时间推移出现的实践的观察。顺便说一下,我是最近 PEP 8 更新的合著者之一,我的答案基于自 2002 年以来我在专业使用 Python 时看到 _ 作为变量名的三种不同方式。 - ncoghlan
14
这段话主要讲的是元组解包中的规则,使用a, __, c = iterable这样的写法可以告诉读者我们只需要元组的第一个和最后一个值,而如果写成a, b, c = iterable,读者(或自动化代码检查工具)可能会认为三个变量都会在后面被用到,如果没有使用,可能会提示存在错误。 - ncoghlan
显示剩余23条评论

253

这只是一个变量名,在Python中,使用_表示临时变量是一种惯例。它只是表示循环变量实际上并没有被使用。


7
这句话的意思是“你的意思是它不代表最后一个返回值?”请确认是否正确。 - alwbtc
40
@steve 只能在 Python shell 中执行。 - Gabi Purcaru
4
与 Prolog 中使用 _ 相似 - Matthias
5
类似于Matlab中使用“~”的方法。 - PatriceG
2
请注意,在cpython shell中,如果您明确定义了“_”,它将永久停止保存先前表达式的输出值。这似乎非常不一致,Python语言标准需要解决这个问题。他们应该只将“_”定义为一个可抛弃的名称,并阻止其被用作真正的标识符。 - theferrit32
@theferrit32 这并不是永久性的。请查看我在“如何在交互式会话中重置下划线?”上的回答 - wjandrea

133

在Python中,下划线 _ 被认为是“我不关心”或“临时变量”。

  • The python interpreter stores the last expression value to the special variable called _.

    >>> 10 
    10
    
    >>> _ 
    10
    
    >>> _ * 3 
    30
    
  • The underscore _ is also used for ignoring the specific values. If you don’t need the specific values or the values are not used, just assign the values to underscore.

    Ignore a value when unpacking

    x, _, y = (1, 2, 3)
    
    >>> x
    1
    
    >>> y 
    3
    

    Ignore the index

    for _ in range(10):     
        do_something()
    

4
有第三种用法,即用于国际化函数 _("Hello world!") - Jeff Younker
11
在处理器级别上,“for _ in range” 和 “for x in range” 然后不使用 x,实际上是否有区别?或者这只是为了提高人类的可读性? - iammax
10
使用dis模块后,我发现字节码没有任何区别。然而,人类可读性的好处是显而易见的。 - Alistair Carscadden
为什么如果我使用 print 命令打印某个值,它不会显示出来? - ado sar
1
@ado 你是什么意思?你在打印什么,而且你期望看到什么准确的结果?如果你输入 >>> 10 然后 >>> print(_),那么10将会被打印出来,如果这就是你的意思的话。 - wjandrea

33

在 Python 中使用下划线的情况有五种。

  1. 用于存储解释器中最后一个表达式的值。

  2. 用于忽略特定的值(所谓的“我不关心”)。

  3. 将变量或函数的名称赋予特殊的意义和功能。

  4. 用作“国际化(i18n)”或“本地化(l10n)”函数。

  5. 用于分隔数字字面值的位数。

这里是一篇由mingrammer撰写的内容丰富的文章。


2
其实这是相当新的东西。https://www.blog.pythonlibrary.org/2017/01/11/new-in-python-underscores-in-numeric-literals/ - MichaelChirico
3
数字3和5并不适用于这个问题。OP询问单个下划线作为独立名称的情况,但第3点谈到使用下划线作为更大名称的一部分,第5点谈到使用它作为字面量而不是名称。我只是提醒一下,以防有新手感到困惑。编辑答案以澄清可能会有所帮助。 - wjandrea

13

就Python语言而言,_通常没有特殊含义。它是一个有效的标识符,就像_foofoo__f_o_o_一样。
唯一的例外是自Python 3.10起的match语句:

match语句中的case模式中,_是一个软关键字,表示通配符。来源

否则,_的任何特殊含义都纯粹是按照惯例而定的。有几种情况很常见:

  • 当变量不打算使用时,但是语法/语义需要一个名称时,可以使用虚拟名称。

    # 迭代忽略内容
    sum(1 for _ in some_iterable)
    # 解包忽略特定元素
    head, *_ = values
    # 函数忽略其参数
    def callback(_): return True
    
  • 许多REPL/shell将最后一个顶级表达式的结果存储到builtins._中。

    特殊标识符_用于交互式解释器中存储上次评估的结果;它存储在builtins模块中。当不处于交互模式时,_没有特殊含义并且未定义。[source]

    由于名称查找的方式,除非被全局或本地_定义遮蔽,否则裸体的_指的是builtins._

    >>> 42
    42
    >>> f'the last answer is {_}'
    'the last answer is 42'
    >>> _
    'the last answer is 42'
    >>> _ = 4  # 使用全局“_”遮蔽“builtins._”
    >>> 23
    23
    >>> _
    4
    

    注意:一些shell(如ipython)不会分配给builtins._,而是特殊处理_

  • 在国际化和本地化的上下文中,_用作主要翻译函数的别名。

    gettext.gettext(message)

    基于当前全局域、语言和区域设置目录,返回消息的本地化翻译。该函数通常在本地命名空间中别名为_()(请参见下面的示例)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接