Reputation: 15718
I was much surprised by this
>>> def f(arg=['local variable']):
... arg.append('!')
... print arg
...
>>> f()
['local variable', '!']
>>> f()
['local variable', '!', '!']
>>> f()
['local variable', '!', '!', '!']
I'm sure this is by design, but WTF?!? And how should I flush the local namespace, so I'm not surprised in the future?
[EDIT]:
Thank you for the explanation about why this happen. But on a practical level, what is the right way of dealing with it? Just deepcopy all default variables before handling them, like below?
>>> from copy import deepcopy
>>> def f(arg=['local variable']):
... arg = deepcopy(arg)
... arg.append('!')
... print arg
...
>>> f()
['local variable', '!']
>>> f()
['local variable', '!']
>>> f()
['local variable', '!']
Upvotes: 2
Views: 907
Reputation: 9609
The local variables are not there any more. The problem is a bit more complex.
def f(arg=['local variable'])
defines a method having a parameter with a default value. As you should know, Python does not copy objects but passes references to them. This means there is some object instance created for the default value, and if you do not specify the parameter, reference to it is passed in the parameter (ie. the instance is not copied). This is usually pretty intuitive if the object is immutable (such as strings) but a list is mutable. When you mutate it, you change the instance that is used for the default value and so all subsequent calls will see that.
You can better imagine it if you think of the function as a class instance (which it actually is because everything in Python is an object):
class _f:
__arg = ['local variable']
def __call__(self, arg = __arg):
# The method body
f = _f()
Now you can see that the default parameter instance has actually the same lifetime as the function itself.
The best way to avoid this problem is to use immutable objects so instead of a list, use a tuple, and instead of a class instance, use None
and construct an instance in the method:
def f(arg=('local variable',)):
arg=list(arg)
Upvotes: 3