82
votes

When "deconstructing" a tuple, I can use _ to denote tuple elements I'm not interested in, e.g.

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

Using Python 2.x, how can I express the same with function arguments? I tried to use underscores:

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

I also tried to just omit the argument altogether:

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

Is there another way to achieve the same?

7
Why not just have default values for your arguments? Why would you have unused arguments in a function? - jamylak
@jamylak: I use a framework which expects me to pass callables in various places. However, in plenty of cases, I don't actually need all arguments passed by the framework. - Frerich Raabe
@FrerichRaabe if the framework requires particular arguments then it would seem cleanest just to use the same names that the framework defines for each argument whether or not the function uses them. That also means you don't have to change the signature of your function when you later discover you did need the other arguments after all. - Duncan
@jamylak For a fellow colleague (and tools like pylint) it's not clear though whether the variables are intentionally unused. So you'd end up adding some sort of comment -- I'd like to avoid that if possible by expressing this in the code itself. - Frerich Raabe
@jamylak I wasn't argueing in favor of the answer which proposed to use del (I also don't like it myself), I was argueing against giving the arguments plausible names but then simply not using them since tools as well as colleagues will probably raise their (electronic) eyebrows over this. Of course I can always document my intentions as English text, but I'd prefer something which expresses it in Python. - Frerich Raabe

7 Answers

34
votes

Here's what I do with unused arguments:

def f(a, *unused):
    return a
115
votes

A funny way I just thought of is to delete the variable:

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

This has numerous advantages:

  • The unused variable can still be used when calling the function both as a positional argument and as a keyword argument.
  • If you start to use it later, you can't since it's deleted, so there is less risk of mistakes.
  • It's standard python syntax.
  • PyCharm does the right thing! (As of 2020, PyCharm no longer does the right thing :( tracking this at https://youtrack.jetbrains.com/issue/PY-39889 )
  • PyLint won't complain and using del is the solution recommended in the PyLint manual.
57
votes

The underscore is used for things we don't care about and the * in *args denotes a list of arguments. Therefore, we can use *_ to denote a list of things we don't care about:

def foo(bar, *_):
    return bar

It even passes PyCharm's checks.

40
votes

You can use '_' as prefix, so that pylint will ignore these parameters:

def f(a, _b, _c):
1
votes

If you have both args and keyword arg you should use

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

In order to avoid "unused variable" inspection messages for unused *args and/or **kwargs, I replace args and kwargs by _ and __ :

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

In addition to remove messages, it clearly shows that you don't care about these arguments.

I can't say if it is a really universal solution, but it worked everywhere I've used it until now.

0
votes

I think the accepted answer is bad, but it can still work, if you use what I should call "Perl way" of dealing with arguments (I don't know Perl really, but I quit trying to learn it after seeing the sub syntax, with manual argument unpacking):

Your function has 3 arguments - this is what it gets called with (Duck typing, remember?). So you get:

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

2 unused parameters. But now, enter improved larsmans' approach:

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

And there go the warnings...

However, I still enjoy more the boxed's way:

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

It keeps the self-documenting quality of parameter names. They're a feature, not a bug.

But, the language itself doesn't force you there - you could also go the other way around, and just let all your function have the signature (*args, **kwargs), and do the argument parsing manually every time. Imagine the level of control that gives you. And no more exceptions when being called in a deprecated way after changing your "signature" (argument count and meaning). This is something worth considering ;)