如何表示未使用的函数参数?


78

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

>>> 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

还有另一种方法可以达到相同目的吗?


4
为什么不仅仅为您的参数提供默认值?为什么在函数中会有未使用的参数?
jamylak'4

5
@jamylak:我使用一个框架,希望我在各个地方传递可调用对象。但是,在很多情况下,我实际上并不需要框架传递的所有参数。
Frerich Raabe'4

5
@FrerichRaabe如果框架需要特定的参数,那么看起来似乎最干净的就是仅使用框架为每个参数定义的相同名称,无论函数是否使用它们。这也意味着当您以后发现您确实确实需要其他参数时,就不必更改函数的签名。
Duncan'4

2
@jamylak对于一个同事(以及像pylint这样的工具),虽然变量是否被有意使用尚不清楚。因此,您最终要添加某种注释-如果可能的话,我想通过在代码本身中表达这一点来避免这种情况。
Frerich Raabe

1
@jamylak我不是反对提议使用的答案del(我自己也不喜欢),我是反对给论据提供合理的名称,但只是不使用它们,因为工具以及同事可能会使用为此引起他们的(电子)关注。当然,我总是可以用英语记录我的意图,但是我更喜欢用Python表达它的东西。
Frerich Raabe

Answers:


30

这是我对未使用的参数的处理:

def f(a, *unused):
    return a

2
嗯,很好!甚至适用于lambda。但是,如果我想忽略第一个和第三个参数而不是第二个参数,该怎么办?
Frerich Raabe'4

1
@FrerichRaabe:那么您仍然必须写出第一个。对于那个很抱歉。
Fred Foo 2012年

我懂了。可惜,就我而言,它实际上是我要忽略的前(或前两个)参数。不过,您的方法还是值得了解的,感谢您的分享!向我+1。
Frerich Raabe '04年

2
@JoelCornett:我不确定我是否理解。也许是因为我缺乏Python专业知识-我使用的框架要求我传递带有四个参数的可调用对象。该框架最终将我的函数调用为f(a,b,c,d)。它似乎并没有明确命名参数-kwargs在这种情况下,对我有帮助吗?也许框架不是最理想的,但我能说什么-我必须使用给出的东西。:-}
Frerich Raabe '04年

1
@JoelCornett:那就是我现在正在做的。只是有些参数的名称很长,所以我考虑将它们缩写为某些内容-例如_-这样我就可以看到传递了一个变量-我只是碰巧不需要它(现在)。
Frerich Raabe '04年

105

我刚刚想到的一种有趣的方式是删除变量:

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

这具有许多优点:

  • 将函数同时用作位置参数和关键字参数时,仍可以使用未使用的变量。
  • 如果您以后开始使用它,则由于将其删除而无法使用,因此发生错误的风险较小。
  • 这是标准的python语法。
  • PyCharm做正确的事!(从2020年开始,PyCharm不再做正确的事情:(在https://youtrack.jetbrains.com/issue/PY-39889上进行跟踪)
  • PyLint不会抱怨,使用PyLint手册中del推荐的解决方案。

2
我非常喜欢小费,并会采用它。我仍然会添加一个小注释,例如,# Ignored parameters.因为意图并不是真的要“删除”变量。
Teebrin 2014年

6
太好了,这是唯一的答案,它处理未使用的参数,而不是尾随。其他的则应删除或删除;)
Tomasz Gandor

1
优化程序是否检测到此?
Pepedou '16

1
@Pepedou可能目前不在典型情况下。在del自身负责“释放”的说法(因此,如果没有其他引用它变得适合垃圾收集)。唯一的其他开销是参数传递本身,这应该忽略不计,但如果没有整个程序分析就无法优化,这是:1)查找并更改每个调用方以不传递那些参数; 2)确保那些优化的调用方不会调用函数那仍然使用这些参数在这种优化的方式,和3)证明该功能没有其他调用者的存在。(续)
mtraceur

1
@Pepedou(续)但是Python非常动态,以至于一般情况下第三个要求基本上是不可能的。“足够先进的假设优化器”可以创建进行某些假设的代码,进行这些优化,检查这些假设,在失败时提供一些备用代码。这已经进入了“热点优化”和“及时编译”的阶段,像PyPy这样的其他Python实现已经完成了一些工作。TL; DR:我不希望对未使用的参数进行优化,但是我也认为开销完全可以忽略不计。
mtraceur

54

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

def foo(bar, *_):
    return bar

它甚至可以通过PyCharm的检查。


这在Python 3的
安德烈亚斯讨厌审查

5
我使用_namelike_rubbish作为丢弃参数,原因有以下三个:a)Pycharm不再显示警告。b)我记得我扔掉的东西。c)单个下划线不存在冲突。
Thinkeye

_name用于表示半私有变量/类属性。在这里使用它没有意义,因为目标是忽略输入。但是,它意义不大,以致不太可能与_name的常规用法引起混淆。
保罗·布朗

1
这是pylint使用的默认设置,ignored-argument-names=_.*允许不使用args匹配模式
Anentropic

这两种约定相去甚远:对于外部名称,即类,函数和方法名称,加引号的下划线表示“除非您知道自己在做什么,否则请勿触摸”。对于局部变量-前划线表示“未使用”。但是,对于争论,它们确实会发生冲突。参数成为Python中的局部变量,但如果调用者按名称传递参数,则它们成为函数外部接口的一部分。在这种情况下,您无权重命名它们。更糟糕的是,_arg约定用来表示“可选的私有参数,除非您知道自己在做什么,否则不要通过”。
贝尼·切尔尼亚夫斯基-帕斯金,

36

您可以使用'_'作为前缀,这样pylint将忽略以下参数:

def f(a, _b, _c):

1

如果同时具有args和关键字arg,则应使用

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

我觉得在pylint中应该有一个配置设置,通常*args, **kwargs在您可能不使用或不关心它们的函数上接受全部捕获
Anentropic

1
将所有可能存在于宇宙中的论点放到地板上是一个可怕的建议。
盒装

0

我认为公认的答案很不好,但是,如果您使用我所说的“ 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),并每次都手动进行参数解析。想象一下您所拥有的控制水平。在更改“签名”(参数计数和含义)后以不推荐使用的方式调用时,也不会再有例外。这是值得考虑的;)


1
我认为您# unused发表评论的事实暗示着它实际上并不是那样的自我记录或惯用语del
Frerich Raabe 2015年

好的,我删除了评论。现在的确是自我记录。(而且很认真:您在争论“忽略”不是自记录的。我不在乎忽略是否是自记录的,而是API是否是自记录的)。
Tomasz Gandor

1
这不会使API自行记录。此外,已完成的工作已经完成且无法撤销:您认为首先有必要写评论这一事实表明,实际上尚不清楚del正在做什么。还是您认为,如果从代码中删除注释,模糊代码会变得不太模糊?
乔纳森·

在这种情况下,您不了解“自我记录API”的含义:这意味着以下事实:1)存在,其编号已知;2)有有意义的名字。API的意思是“接口”,功能签名。该def(..)行下的内容-是否评论-不相关。
Tomasz Gandor

0

为了避免对未使用的* args和/或** kwargs发出“未使用的变量”检查消息,我用args和替换kwargsby___

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

除了删除消息外,它还清楚表明您不关心这些参数。

我不能说这是否是一个真正的通用解决方案,但直到现在我一直在使用它。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.