【问题标题】:What is the purpose of the single underscore "_" variable in Python?Python中单个下划线“_”变量的目的是什么?
【发布时间】:2011-08-19 02:05:39
【问题描述】:

这段代码中for后面的_是什么意思?

if tbh.bag:
    n = 0
    for _ in tbh.bag.atom_set():
        n += 1

【问题讨论】:

  • 对于您的情况,len(tbh.bag.atom_set())(如果返回值具有 __len__ 方法)或 sum(1 for _ in tbh.bag.atom_set()) 会更干净
  • pylint 中,虚拟变量名称的另一个选项是变量名称的前缀dummy_。将此前缀与pylint 一起使用,会使pylint 不会发出警告。您还可以为pylint 配置虚拟变量模式以适应__ 之类的内容。

标签: python variables naming-conventions metasyntactic-variable


【解决方案1】:

_ 在 Python 中有 3 个主要的常规用法:

  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 翻译的代码块中将 _ 用作一次性变量(许多人更喜欢双下划线,@ 987654332@,正是出于这个原因,作为他们的一次性变量)。

    Linter 通常会识别这种用例。例如,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 将满足正在使用该名称的 linter,立即清除对对象的引用。 p>

【讨论】:

  • 能否解释一下它在函数调用中的工作原理,例如:raise forms.ValidationError(_("请输入正确的用户名"))。我在 Django 代码中看到过这个,不清楚是怎么回事。
  • 这是用法 2 - 按照惯例,_ 是用于执行国际化和本地化字符串翻译查找的函数的名称。我很确定是 C gettext 库建立了这个约定。
  • FWIW,我个人已经开始使用 __(双下划线)作为我的通用一次性变量,以避免与前两个用例中的任何一个发生冲突。
  • 新兴社区公约往往没有权威来源 - 只是对随着时间的推移出现的实践的观察。 FWIW,我是最近 PEP 8 更新的合著者之一,我的回答基于自 2002 年我开始专业使用 Python 以来,我看到的 3 种不同的方式 _ 用作变量名。
  • 约定主要用于元组解包:a, __, c = iterable 立即告诉读者我们正在解包 3 元组,但仅使用第一个和最后一个值。如果我们改为写a, b, c = iterable,读者(或自动代码检查器)可以合理地期望所有abc在以后使用(如果不是,它可能是某处存在错误的迹象)。
【解决方案2】:

就 Python 语言而言,_ 没有特殊含义。它是一个有效的identifier,就像_foofoo__f_o_o_

_ 的任何特殊含义纯属约定俗成。几种情况很常见:

  • 不打算使用变量但语法/语义需要名称时的虚拟名称。

      # iteration disregarding content
      sum(1 for _ in some_iterable)
      # unpacking disregarding specific elements
      head, *_ = values
      # function disregarding its argument
      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  # shadow ``builtins._`` with global ``_``
      >>> 23
      23
      >>> _
      4
    

    注意:某些 shell,例如 ipython 不分配给 builtins._,而是特殊情况下的 _

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

    gettext.gettext(message)

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

【讨论】:

    【解决方案3】:

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

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

    2. 用于忽略特定值。 (所谓“我不在乎”)

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

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

    5. 将数字字面值的数字分开。

    Here 是一篇不错的文章,其中包含mingrammer 的示例。

    【讨论】:

    • 数字 3 和 5 并不真正适用于这个问题。 OP 询问单个下划线作为独立名称,但第 3 点谈到使用下划线作为更大名称的一部分,第 5 点谈到在文字中使用它,而不是名称。我只是提一下,以防任何新手感到困惑。可能有助于edit 澄清它的答案。
    【解决方案4】:

    下划线 _ 在 Python 中被视为“I don't Care”或“Throwaway”变量

    • python 解释器将最后一个表达式值存储到名为_ 的特殊变量中。

      >>> 10 
      10
      
      >>> _ 
      10
      
      >>> _ * 3 
      30
      
    • 下划线_ 也用于忽略特定值。如果您不需要特定的值或没有使用这些值,只需将值分配给下划线即可。

      解压时忽略一个值

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

      忽略索引

      for _ in range(10):     
          do_something()
      

    【讨论】:

    • 还有第三种用法,用于国际化函数_("Hello world!")
    • 在处理器级别,“for _ in range”和“for x in range”然后不使用 x 之间实际上有区别吗?还是只是为了人类可读性?
    • @iammax 使用dis 模块我发现字节码没有区别。然而,人类可读性的好处是显而易见的。
    【解决方案5】:

    它只是一个变量名,在python中使用_作为一次性变量是常规的。它只是表明循环变量实际上没有被使用。

    【讨论】:

    • 你的意思是它不代表最后的返回值?
    • @steve 仅在 python shell
    • 类似于Prolog中_的使用
    • 类似于Matlab中~的使用
    • 请注意,在 cpython shell 中,如果您明确定义 _,它将永久停止保存前一个表达式的输出值。这似乎非常不一致,Python 语言标准需要解决这个问题。他们应该将_ 定义为一次性名称,并阻止它被用作真正的标识符。
    猜你喜欢
    • 2022-03-02
    • 2022-03-02
    • 2010-12-05
    • 1970-01-01
    • 2022-01-07
    相关资源
    最近更新 更多