Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Erroneous unused-variable (false positive) in lambda with *args and default argument #3866

Closed
pganssle opened this issue Sep 29, 2020 · 0 comments · Fixed by #7104
Closed
Labels
False Positive 🦟 A message is emitted but nothing is wrong with the code

Comments

@pganssle
Copy link

When running pylint over the following function, it warns that the variable variable (the one defined in the function, not the parameter), is unused:

def lambda_with_args():
    variable = 1
    return lambda *_, variable=variable: variable + 1

I see the same issue when you add **kwargs and/or other parameters to the lambda:

def lambda_with_args_kwargs():
    variable = 1
    return lambda *_, variable=variable, **_kwargs: variable + 1

The expected behavior is that variable should be considered used, since it is used to set the default argument for variable in the lambda. This is actually a fairly common idiom to get "early-binding" behavior in lambdas (though having *args in a lambda is considerably less common, so I'm not entirely shocked that — as far as I saw — this hasn't been reported before).

With some further explorations, I have determined:

  1. Multiple non-*args arguments, or **kwargs alone is not enough to trigger this bug.

  2. Replacing the lambda with the equivalent def statement also won't trigger the bug:

    def func_def():
        variable = 1
        def f(*_, variable=variable):
            return variable + 1
        return f
  3. If you change the name of the variable that variable gets bound to, it also won't trigger the bug (lambda *args, var=variable: var + 1 works fine).

Here is a minimal Python file that shows all of these properties:

# pylint: disable=missing-module-docstring, missing-docstring
# pylint: disable=invalid-name

# These trigger the bug
def lambda_with_args():
    variable = 1
    return lambda *_, variable=variable: variable + 1

def lambda_with_args_kwargs():
    variable = 1
    return lambda *_, variable=variable, **_kwargs: variable + 1

def lambda_with_args_and_multi_args():
    variable = 1
    return lambda *_, a, variable=variable: variable + a


# The rest of these do not trigger the bug
def lambda_with_multi_args():
    variable = 1
    return lambda a, variable=variable: variable + a

def lambda_without_args():
    variable = 1
    return lambda variable=variable: variable + 1

def lambda_with_kwargs():
    variable = 1
    return lambda variable=variable, **_: variable + 1

def func_def():
    variable = 1
    def f(*_, variable=variable):
        return variable + 1

    return f

def different_name():
    variable = 1
    return lambda *args, var=variable: var + 1

pylint --version output

pylint 2.6.0
astroid 2.4.2
Python 3.8.2 (default, Apr 18 2020, 12:47:51) 
[GCC 9.3.0]

Doing a bit more digging, it seems that prior to pylint==2.6.0, this bug also affected the def f(*_, variable=variable) variant, and in earlier versions even more erroneous warnings were raised as well. Not entirely sure, but I suspect #3713 fixed the issue for the def version of this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
False Positive 🦟 A message is emitted but nothing is wrong with the code
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants