TIL: python gotchas
Thanks to 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:
Here, 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?
Output:
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:
However, 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.