【问题标题】:How can I denote unused function arguments?如何表示未使用的函数参数?
【发布时间】:2012-04-05 09:04:05
【问题描述】:

当“解构”一个元组时,我可以使用_ 来表示我不感兴趣的元组元素,例如

>>> a,_,_ = (1,2,3)
>>> a
1

使用 Python 2.x,我如何用函数参数表达相同的意思?我尝试使用下划线:

>>> def f(a,_,_): return a
...
  File "<stdin>", line 1
SyntaxError: duplicate argument '_' in function definition

我也试图完全省略这个论点:

>>> def f(a,,): return a
  File "<stdin>", line 1
    def f(a,,): return a
        ^
SyntaxError: invalid syntax

还有其他方法可以达到同样的效果吗?

【问题讨论】:

  • 为什么不给你的参数设置默认值呢?为什么函数中有未使用的参数?
  • @jamylak:我使用了一个框架,它希望我在不同的地方传递可调用对象。但是,在很多情况下,我实际上并不需要框架传递的所有参数。
  • @FrerichRaabe 如果框架需要特定的参数,那么无论函数是否使用它们,使用框架为每个参数定义的相同名称似乎是最干净的。这也意味着当您后来发现确实需要其他参数时,您不必更改函数的签名。
  • @jamylak 对于一位同事(以及诸如 pylint 之类的工具)来说,不清楚这些变量是否是有意未使用的。所以你最终会添加某种注释——如果可能的话,我想通过在代码本身中表达这一点来避免这种情况。
  • @jamylak 我并不赞成建议使用del 的答案(我自己也不喜欢它),我反对给论点提供合理的名称,但随后只是简单地不使用它们,因为工具和同事可能会对此提出(电子)眉毛。当然,我总是可以将我的意图记录为英文文本,但我更喜欢用 Python 表达它的东西。

标签: python python-2.x


【解决方案1】:

我刚刚想到的一个有趣的方法是删除变量:

def f(foo, unused1, unused2, unused3):
    del unused1, unused2, unused3
    return foo

这有很多优点:

  • 在调用函数时,仍然可以使用未使用的变量作为位置参数和关键字参数。
  • 如果你以后开始使用它,你不能因为它被删除了,所以出错的风险更小。
  • 这是标准的 Python 语法。
  • PyCharm 做对了! (截至 2020 年,PyCharm 不再做正确的事 :( 在 https://youtrack.jetbrains.com/issue/PY-39889 跟踪此问题)
  • PyLint 不会抱怨,使用delPyLint manual 中推荐的解决方案。

【讨论】:

  • 我非常喜欢这个技巧并且会采纳它。我仍然会添加一个小评论,例如# Ignored parameters.,因为其意图并不是真正“删除”变量。
  • 太好了,这是处理 LEADING 未使用参数的唯一答案,而不是尾随。其他人应该被否决或删除;)
  • 优化器是否检测到这一点?
  • @Pepedou 目前可能不是典型情况。 del 本身负责“释放”参数(因此,如果没有其他东西引用它,它就有资格进行垃圾收集)。唯一的其他开销是传递自身的参数,它应该可以忽略不计,但如果没有整个程序分析就无法优化掉 1)查找并更改每个调用者以不传递这些参数,2)确保那些优化的调用者不会调用函数do 仍然以这种优化的方式使用这些参数,并且 3) 证明该函数的其他调用者不存在。 (续)
  • @Pepedou (cont) 但是 Python 是如此动态,以至于第三个要求在一般情况下基本上是不可能的。 “足够先进的假设优化器”可以创建做出一些假设的代码,进行这些优化,并且检查这些假设,并且有一些失败时的后备代码。这涉及到“热点优化”和“即时编译”——像 PyPy 这样的其他 Python 实现已经做了一些。 TL;DR:我不希望优化未使用的参数,但我也认为开销完全可以忽略不计。
【解决方案2】:

下划线用于我们不关心的事情,*args 中的 * 表示参数列表。因此,我们可以使用 *_ 来表示我们不关心的事物的列表:

def foo(bar, *_):
    return bar

它甚至通过了 PyCharm 的检查。

【讨论】:

  • 在 Python 3 中。
  • 我使用_name_rubbish 一样作为一次性参数,原因有以下三个:a) Pycharm 不再显示警告。 b) 我记得我扔掉的什么。 c) 与单个下划线没有冲突。
  • _name 用于表示半私有变量/类属性。在这里使用它没有意义,因为目标是忽略输入。但是,它没有什么意义,因此不太可能与 _name 的传统用法混淆。
  • 这是 pylint 使用的默认值,允许不使用匹配 ignored-argument-names=_.* 模式的参数
  • 这两种约定没有太大冲突:对于外部名称,即类、函数和方法名称,前导下划线表示“除非你知道自己在做什么,否则不要触摸”;对于局部变量——前导下划线表示“未使用”。但是,对于争论,它们确实会发生冲突。参数成为局部变量,但在 Python 中,如果调用者按名称传递它们,它们函数外部接口的一部分。在这种情况下,您无权重命名它们。更糟糕的是,_arg 约定用于表示“可选的私有 arg,除非你知道自己在做什么,否则不要通过”。
【解决方案3】:

你可以使用'_'作为前缀,这样pylint会忽略这些参数:

def f(a, _b, _c):

【讨论】:

    【解决方案4】:

    这是我对未使用的参数所做的:

    def f(a, *unused):
        return a
    

    【讨论】:

    • 嗯,不错!甚至可以使用 lambdas。但是,如果我想忽略第一个和第三个参数而不是第二个参数怎么办?
    • @FrerichRaabe:那么您仍然必须写出第一个。对此感到抱歉。
    • 我明白了。可惜,就我而言,这实际上是我想忽略的第一个(或前两个)论点。不过,你的方法很高兴知道,谢谢分享!来自我的 +1。
    • @JoelCornett:我不确定我是否理解。也许是我缺乏 Python 专业知识 - 我使用的框架要求我传递一个带有四个参数的可调用对象。该框架最终会调用我的函数,例如f(a,b,c,d)。它似乎没有明确地命名参数 - 在这种情况下我会使用 kwargs 帮助吗?也许这个框架不是最理想的,但我能说什么——我必须使用我得到的东西。 :-}
    • @JoelCornett:这就是我现在所做的。只是有些参数的名称很长,所以我考虑将它们缩短为一些东西 - 比如说,_ - 这样我就可以看到有一个变量正在传递 - 我只是碰巧不需要它(现在)。
    【解决方案5】:

    为了避免未使用 *args 和/或 **kwargs 的“未使用变量”检查消息,我将 argskwargs 替换为 ___

    def f(a, b, *_, **__):
        ...
    

    除了删除消息之外,它清楚地表明你不关心这些论点。

    我不能说它是否是一个真正通用的解决方案,但它在我使用它的任何地方都有效。

    【讨论】:

      【解决方案6】:

      如果你有 args 和关键字 arg 你应该使用

      def f(a, *args, **kwargs):
          return a
      

      【讨论】:

      • 我觉得在 pylint 中应该有一个配置设置,在你可能不使用或不关心它们的功能上接受包罗万象的*args, **kwargs 是很常见的
      • 把宇宙中所有可能的论点都扔到地板上是一个糟糕的建议。
      【解决方案7】:

      我认为接受的答案很糟糕,但它仍然可以工作,如果你使用我应该称之为“Perl 方式”来处理参数(我真的不知道 Perl,但我在看到之后不再尝试学习它sub 语法,带有手动参数解包):

      你的函数有 3 个参数 - 这是它被调用的参数(鸭子打字,还记得吗?)。所以你得到:

      def funfun(a, b, c):
          return b * 2
      

      2 个未使用的参数。但是现在,输入改进的 larsmans 方法:

      def funfun(*args):
          return args[1] * 2
      

      还有警告...

      不过,我还是更喜欢盒装的方式:

      def funfun(a, b, c):
          del a, c
          return b * 2
      

      它保持参数名称的自记录质量。它们是功能,而不是错误。

      但是,语言本身并不会强迫你去那里——你也可以反过来,让你的所有函数都有签名(*args, **kwargs),并且每次都手动解析参数。想象一下给您带来的控制水平。在更改“签名”(参数计数和含义)后以不推荐的方式调用时不再有例外。这是值得考虑的事情;)

      【讨论】:

      • 我认为您写了 # unused 评论这一事实暗示,像这样使用 del 实际上并不是自我记录或惯用的。
      • 好的,我删除了评论。现在它确实是自我记录。 (而且说真的:你在争论“忽略”不是自记录的。我不在乎忽略是否是自记录的,但如果 API 是自记录的)。
      • 这不会使 API 自我记录。此外,已完成且无法撤消:您认为有必要首先写评论这一事实表明,del 正在做什么实际上并不清楚。或者你认为如果你从中删除 cmets,晦涩的代码会变得不那么晦涩吗?
      • 你不明白在这种情况下“自我记录 API”是什么意思:这意味着参数:1)存在,它们的数量是已知的; 2) 有有意义的名字。 API的意思是“接口”,函数签名。 def(..) 行下方的内容 - cmets 与否 - 不相关。
      猜你喜欢
      • 1970-01-01
      • 2020-10-04
      • 1970-01-01
      • 2018-02-13
      • 2018-05-24
      • 2020-03-14
      • 2020-03-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多