1

I've read in Expert Python Programming about this edge case. Check this code:

def f(arg={}):
    arg['3'] = 4
    return arg

>>> print f()
{'3': 4}
>>> res = f()
>>> res['4'] = 'Still here'
>>> print f()
{'3': 4, '4': 'Still here'}

It's not clear to me why when f gets called the last time (after its return value has been saved), instead of assigning arg the empty dict (since it was called with no arguments), it keeps the old reference.

The book says so: "if an object is created within the arguments, the argument reference will still be alive if the function returns the object".

I understand that "this is the way it works", but why so?

Mihnea DB
  • 386
  • 3
  • 9

3 Answers3

2

Your problem is defaulting to a mutable argument (dictionary in this case):

def f(arg={}):
    arg['3'] = 4
    return arg

should be:

def f(arg=None):
    arg = arg if arg is not None else {}
    arg['3'] = 4
    return arg

yields:

>>> print f()
{'3': 4}
>>> res = f()
>>> res['4'] = 'Still here'
>>> print f()
{'3': 4}

like you'd expect.

The issue here is the default arguments are evaluated when the function is first defined/parsed, not when they are called. It's just a nuance of the python parser that you need to be aware of.

For the why, check out "Least Astonishment" and the Mutable Default Argument

Community
  • 1
  • 1
Sam Dolan
  • 31,966
  • 10
  • 88
  • 84
2

Because the default arguments are evaluated once only, when the function is evaluated and created (they are part of the function defenition and can be fetched through inspect.getargspec, for example).

Since they are part of the function, every call to the function will have the same instance of the default value. This is not a problem if it is an immutable value, but as soon as it is mutable it can become a gotcha.

The same 'feature' exist in class defenitions, given a class defenition:

class A(object):
    foo = {}

calling

x = A() 
y = A()
x.foo['bar'] = "baz"

...would give that y.foo['bar'] evaluates to "baz", since x and y has the same foo. This is why member initialization should be done in init instead of the class body.

Fredrik Håård
  • 2,856
  • 1
  • 24
  • 32
  • 1
    "member initialisation shoudl be done in `__init__`: Unless you actually want to create a class member, rather than an instance member, of course. – Pete Feb 09 '12 at 17:29
1

The default parameter gets created once, when the functon is declared, so every call to f() gets the same instance of a dictionary, which starts out empty. Does that answer the question?

Pete
  • 1,241
  • 2
  • 9
  • 21