Python Functions Defaults Explained

I have been on the several Python interviews again and have passed an Upwork Python test. And I have noticed that the interviewers like using task as the following one.

Photo by Joanna Kosinska on Unsplash
def f(x, l=[]):
for i in range(x):
l.append(i * i)
return l
>>> f(2)
>>> f(3, [0, 1, 2])
>>> f(3)

Question: what is the output of those lines?


The output of the first two lines is pretty obvious, but the result of the third line f(3) wasn’t so intuitive for me.

So let’s investigate what is going on after the initialization of the f function. I use IPython to run this code.

>>> f
<function __main__.f(x, l=[])>
>>> f.__defaults__
([],)

The empty list that we see from the f.__defaults__ result is basically the l variable in the function code.

>>> f(2)
[0, 1]

Nothing special.

>>> f
<function __main__.f(x, l=[0, 1])>
>>> f.__defaults__
([0, 1],)

But! Now, we can see that variable l has a [0, 1] value because of the mutability of the Python list object and passing function arguments as a reference.

>>> f(3, [0, 1, 2])
[0, 1, 2, 0, 1, 4]
>>> f
<function __main__.f(x, l=[0, 1])>

Nothing special too. Just passing new list object as a l variable.

>>> f(3)
[0, 1, 0, 1, 4]
>>> f
<function __main__.f(x, l=[0, 1, 0, 1, 4])>

And here comes the most interesting part. When you run f(3), Python doesn’t use the empty list that is defined in function code, it uses the l variable with the values from f.__defaults__ ([0, 1]).

P.S.

If you want to have a function that uses empty list after each call, you should use something like this (set `l` default value to `None`).

def f(x, l=None):
if l is None:
l = []
for i in range(x):
l.append(i * i)
return l
>>> f(2)
[0, 1]
>>> f(3, [0, 1, 2])
[0, 1, 2, 0, 1, 4]
>>> f(3)
[0, 1, 4]

Finally

One of the most popular test question from the Python interview was explained here. So it turns out that you can’t always trust your intuition, at least mine :)



Thanks for the attention to the topic, feel free to leave your questions in the comments for discussion.