I understand that one should not use mutable default parameter value in Python (with some exceptions) because this value is evaluated and stored only once when the function is defined, and not each time the function is later called.
My understanding of that is this (using the example below; please excuse my imprecise language as I'm just a beginner in Python programming, who's stuck at the Function chapter of my textbook because of this):
def f(x = [1, 2, 3]):
x.append(4)
print(x)
f()
f()
1) The function f is defined, and x (local variable in f) assumes the default variable of [1, 2, 3] (even before the function is called)
2) When f() is called, x is still [1, 2, 3] due to no argument passed to it, and x continues having its default value
3) x is modified in place with append, becomes [1, 2, 3, 4], and is printed as such
However, this is where my confusion arises. I'd assume that:
4) When f ends, x is destroyed (in the stack or whatever you'd call it) and is no longer associated with the list object [1, 2, 3, 4]**
5) The list object [1, 2, 3, 4] is reclaimed since there's no variable that refers to it anymore
Therefore,
6) When f() is called the second time, I'd expect Python to output an error since x now no longer has a value associated with it. In other words, how can Python reuse the default value from the last evaluation when it's been reclaimed/destroyed?
Appreciate all your help and explanation!
** this understanding I got from Ned Batchelder's page on variable name assignment (see below)
While it may seems to you that at the end of the execution x, the default value, is disposed, it is not.
In fact, Python has a global namespace with all the names available for you to use (built-in functions, classes and functions you import or define).
The content of this namespace is made of objects. Function are objects too.
As a test, if you try this in a script or in the python command line, you will see what I mean:
def f(x = [1, 2, 3]):
x.append(4)
print(x)
print dir(f)
you will see the object nature of the function f. As an objects, the default values are referenced in an attribute, f.func_defaults
, therefore they are always available and if mutable they retain the changes, giving you side effects with you may not want.
EDIT: in python 3 the attribute has been replaced by f.__defaults__
There are two references to the list in your case, one is store in the background of the function as the default value to the argument x
.
When the function is called without x
, a new reference to the same list is created as the local variable x
. Then you append to the list via the second reference. And after the call, the second reference is garbage collected. The first reference still points to the same list, which has one element more now.
Or in short: there is only one list all the time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With