DEV Community

Jota Feldmann
Jota Feldmann

Posted on • Edited on

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

Top comments (0)