4

Consider the following code:

def f(a=[]):
  print(a)
  a += [1]

f()
f()
f()

which outputs

[]
[1]
[1,1]

This behavior seems peculiar. Shouldn't the parameter a be reset to [] each time the function runs? When the parameter is an integer I get the expected behavior:

def f(a=1):
  print(a)
  a += 1

f()
f()
f()

outputs

1
1
1

I realize lists are mutable and integers aren't, but I can't figure out if that would matter here. Thank you.

  • https://stackoverflow.com/questions/366422/what-is-the-pythonic-way-to-avoid-default-parameters-that-are-empty-lists It looks like your question was asked and answered before. – H. McClelland May 11 '21 at 03:57
  • Welcome aboard but it will probably be closed as a duplicate. No fault of yours, but this question is frequent with Python and has been asked before and Stackoverflow tries to avoid duplicates. In any case, dupe or not you will hopefully have found the answers helpful. – JL Peyret May 11 '21 at 04:01

2 Answers2

2

No. It's a foible of Python that mutable object initializers do this. It's a better pattern to use None and set the initial value in the method body:

def f(a=None):
  if a is None:  
    a = []
  print(a)
  a += [1]

If you use pylint, it provides a warning dangerous-default-value (W0102).

Gene
  • 46,253
  • 4
  • 58
  • 96
2

This is a little gotcha in Python. A default parameter doesn't just set a default, it captures an object. That is, as you can see, the default parameter is one specific list object that happens to be initialized empty. You might think you could do this:

def f(a=[]):
    a = a[:]

but if you do that, then any time someone passes in a list, you'll make a copy, and your changes won't be seen in the original list. This is sometimes a good choice:

def f(a=None):
    if not a:
        a = []
Tim Roberts
  • 48,973
  • 4
  • 21
  • 30