2

The following warning is in the Default Values in Function Arguments section in Python Docs.

Important warning: The default value is evaluated only once. This makes a difference when the default is a mutable object such as a list, dictionary, or instances of most classes. For example, the following function accumulates the arguments passed to it on subsequent calls:

def f(a, L=[]):
    L.append(a)
    return L

print(f(1))
print(f(2))
print(f(3))

This will print

[1]

[1, 2]

[1, 2, 3]

If you don’t want the default to be shared between subsequent calls, you can write the function like this instead:

def f(a, L=None):
    if L is None:
        L = []
    L.append(a)
    return L

I didn't quite understand how the L=None part of code solves this problem. Can you help me understand. Thanks

HopeKing
  • 3,317
  • 7
  • 39
  • 62

3 Answers3

2

None is immutable, meaning it cannot be changed. So if None is set to be the default value of the parameter, it is always the same on every function call, and a new empty list is set to L (because it is evaluated every time, not just the first time the function is called).

Further reading: http://effbot.org/zone/default-values.htm

Miles Winther
  • 134
  • 1
  • 7
1

Like the documentation mentions, when you put L=[] in an argument, the value for the argument is evaluated only one, so the list that L has is created only once and shared between invocations.

So, if what you want is to create a new list every time the function is called, you have to create the list inside the function with a statement like L = []. But if the caller passes a list, you don't want to create a new empty one, you just want to use the one the caller gave you. That's where the None here comes in, it's just a signal that you want an empty list. That's why you do the if to check if the argument is None and create an empty list only when that's true.

An since None is just a value that's immutable, it will not be shared between calls.

André Santos
  • 380
  • 1
  • 4
  • 12
1

Let's talk about the solution first than we will investigate the problem a little!

def f(a, L=None):
    if L is None:
        L = []
    L.append(a)
    return L

When you call without passing L, a new list is being created everytime the function is called. passed value for a is appended to L and newly created L is returned.

This is pretty straightforward. Let's look at what is happening when L has a default value of []

In Python default values for function parameters are evaluated at the time def is evaluated.

You can see that using <function_name>.__defaults__

mahorir@mahorir-Vostro-3446:~$ python3
Python 3.6.9 (default, Apr 18 2020, 01:56:04)

>>> def fun(a,l=[]):
...     l.append(a);return l
... 
>>> fun.__defaults__
([],)

You can see that defaults in the beginning (before calling function is empty list) After few calls -

>>> fun(1)
[1]
>>> fun(2)
[1, 2]
>>> fun(3)
[1, 2, 3]
>>> fun.__defaults__
([1, 2, 3],)

This ofcourse surprises every Python developer!

mahoriR
  • 4,377
  • 3
  • 18
  • 27