A tricky Python default argument

jotafeldmann

Jota Feldmann

Posted on February 15, 2020

A tricky Python default argument

Check the following code:

def append(l=[]):
  l.append(1)
  return l

In my opinion, we have a problematic mutator function, but for the purpose of this article, just focus on the default argument/parameter. What's wrong?

def append(l=[]):
  l.append(1)
  return l

print(append())
# [1]
print(append())
# [1,1]

Here's the tricky default parameter: any object (list, map, etc) will be instantiate and will live in the memory for the rest of the function's life!

IMHO it's problematic behavior, different from any other language, like Java or JavaScript. Ok, it's cool when you can work with dependency injection because once set, it will never be instantiated again. But in common use, you can forget that default parameter and have practical side-effects. Example: in unitary tests (my reason to write that article).

To avoid that stuff, you can check and instantiate every time, at the beginning of the function:

def immutableAppend(l=None):
  l = [] if l is None else l
  l.append(1)
  return l

print(immutableAppend())
# [1]
print(immutableAppend())
# [1]

This gotcha leads me to the great Python Guide, which first gotcha is exactly this behavior. And one more reason to read all Python doc, again 😞 (search for "Important warning: The default value is evaluated only once").

You can test it on https://repl.it/@jotafeldmann/trickyDefaultArgument

💖 💪 🙅 🚩
jotafeldmann
Jota Feldmann

Posted on February 15, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

A tricky Python default argument
python A tricky Python default argument

February 15, 2020