1

The following code

def f(x,l=[]):
    for i in range(x):
        l.append(i*i)
    print(l) 

f(2)
f(3)

outputs

[0, 1]

[0, 1, 0, 1, 4]

And not the trivial

[0, 1]

[0, 1, 4]

This means that the named argument l is actually a single consistent variable THAT DOESN'T GET RESET on new calls to f.

This is obviously not a bug, and is by design.

My question is why is this the desired behavior? To me it seems more confusing than helpful, and this would make me never want to use default values that are not immutable.

Community
  • 1
  • 1
Gulzar
  • 23,452
  • 27
  • 113
  • 201
  • 2
    The default value could be something much more expensive to compute than an empty list literal, in which case you would only want to evaluate it *once*, when you define the function, rather than every single time you *call* the function. – chepner Mar 15 '19 at 15:23
  • Plus, there's already a way to execute code on each call: put it in the body of the function. – chepner Mar 15 '19 at 15:24
  • @chepner about your second comment - obviously putting code in the function body would execute it every call. But is putting a variable in the named arguments really the pythonic way to create a "static" variable? – Gulzar Mar 15 '19 at 15:31
  • @Gulzar making a default arg an immutable type is pythonic. It does not force typing, though, if that's what you mean by *static*. That's why you can have `some_arg=None` and replace it with a different type – C.Nivs Mar 15 '19 at 15:33
  • 1
    @Gulzar The Pythonic way to create a C-style static variable would be to define a method of a class instead. But just because there's no strong or obvious use case for a mutable default argument doesn't mean there is compelling reason to *disallow* it. – chepner Mar 15 '19 at 15:35

1 Answers1

0

Functions are defined once, so when using default args with mutable types, they use a single reference to that default arg (because it's again, defined once). This is why it is bad practice to use lists, dicts, etc as default args over immutable types like None, int, str, etc.

As an example:


def mutable_arg(x=[]):
    x.append(3)
    print(x)

def immutable_arg(x=None):
    x = x or []
    x.append(3)
    print(x)

mutable_arg() # prints [3]
mutable_arg() # prints [3,3]
immutable_arg() # prints [3]
immutable_arg() # prints [3]

In immutable_arg, it's creating a new list for each call, rather than re-using the same default as in mutable_arg

C.Nivs
  • 12,353
  • 2
  • 19
  • 44
  • I understand the mechanism by which this occurs. I also realize why it is bad practice, as explained in the question. I do not, however, understand WHY this is the design choice. Why allow this pitfall in the first place, rather that automatically re-initializing? – Gulzar Mar 15 '19 at 15:28
  • See @chepner's comment, then. Why would you *want* to re-define an argument every time? – C.Nivs Mar 15 '19 at 15:31