pylint, I came across a couple of python gotchas that weren’t obvious to me at first glance.
Dangerous default value as argument
Python allows you to declare a default value for an argument, if it is not supplied by the caller. Like so:
badfunc accepts an argument
nums which is supposed to be a list. If you do not supply anything, this will be initialized to a list. You can do something like this:
The output will be:
If you would not have designated a default value, you could not append to it, since it would have been undefined. So it is useful in that way.
However, there is a strange gotcha hidden here. What happens if you call the function twice in succession?
It appears as though the previous instance of
nums is reused in subsequent calls to the function! I certainly didn’t expect that. It behaves like a static variable inside the function. This unexpected behavior is why
pylint will flag this usage as
warning| Dangerous default value  as argument.
You can avoid this quite easily by rewriting the function like this:
Undefined loop variable
Consider this useless piece of code:
If you run this, it works as expected:
pylint complains that
warning:(undefined-loop-variable) Using possibly undefined loop variable 'fruit' at line 11.
Huh? There is no undefined usage of
fruit. Every time I used it, was inside the loop.
I am unsure why
pylint is freaking out about this, but one theory pointed out by a coworker is that
function_runner() may not execute the supplied lambda immediately. It may be some sort of an async function runner (kind of like
futures). In that case, the function may run when the loop variable
fruit is out of scope.
The proper thing to do here is to pass the function and the argument separately to
function_runner(). That way, the value of the variable will be copied over and you need not worry about lifetimes.