Say we have a function in a file, something like:
..... other fucntions
def add_to_list(l = []):
l.append("foo")
..... other functions
When will def
be called? What exactly does def
do?
Say we have a function in a file, something like:
..... other fucntions
def add_to_list(l = []):
l.append("foo")
..... other functions
When will def
be called? What exactly does def
do?
[] creates a list and, for efficiency reasons, when a list is passed, it isn't duplicated or passed by value; it is sent by reference. A similar thing is happening with this. So, firstly all def's are initialized by Python. Then your code is run. However, the initializer has already created the list.
>>> id(add_to_list())
12516768
>>> id(add_to_list())
12516768
>>> id(add_to_list())
12516768
Excerpt from http://effbot.org/zone/default-values.htm
Notice how they have the same id? That's because it's returning the same instance of list every time. Thus, l = [] isn't creating a new instance at run time. So, we keep on appending to the same instance.
That is why we don't experience this behavior with ints, floats, and etc.
Consider your code:
def add_to_list(l = []):
l.append("foo")
print(l)
add_to_list()
add_to_list()
Then it's output:
['foo']
['foo', 'foo']
Now consider this similar function:
def add_to_list():
l = []
l.append("foo")
print(l)
add_to_list()
add_to_list()
The output will be:
['foo']
['foo']
That's because the l = [] is run after the constructors are initialized (in live time). When you consider the first code, you will see that the constructor is ran first, then the code executes live time.
def is executed whenever you hit it in parsing the source file. It defines the function. This means that the body of the function is assigned to the name, the parameters are included in the "signature" (calling format), etc. IN other words, the function is now ready to call from anywhere below that point, within the scope of the containing program.
Since l is a list, it's bound to whatever you pass into the function call. If you pass in a list, then it's bound by reference to that list, a mutable object.
As to your specific case, there's really no use case that will make sense: since you have to pass an object with an append method, anything you supply will have a value: it will never use the default value. The only way to get that default value into play is to call with empty parentheses, in which case there's no way to get the value back to the calling program (since you return nothing).
Thus, when you call the routine a second time, it appears that you're using the same list you passed the first time. That list already has the "foo" element you added that first time. Here's some test code and the output to illustrate the effect:
def add_to_list(l = []):
l.append("foo")
print "l =", l
empty = []
add_to_list(empty)
print "empty #1", empty
add_to_list(empty)
print "empty #2", empty
add_to_list()
Output:
l = ['foo']
empty #1 ['foo']
l = ['foo', 'foo']
empty #2 ['foo', 'foo']
l = ['foo']
Does that clarify things?