0
votes

After reading this thread, I also tried to get my hands dirty with default arguments. So, following is the same function having the mutable default argument:-

def foo(x = []):
    x.append(1)
    return x

As defined in the docs, the default value is evaluated only once when the function is defined.
So, upon executing this statement, print(foo(), foo(), foo()), I expected the output to be like this: [1] [1, 1] [1, 1, 1]

Instead, this is what I actually got as an output:-

>>> print(foo(), foo(), foo())
[1, 1, 1] [1, 1, 1] [1, 1, 1]

The way the statement is executed (according to me) is that the 1st function call returns [1], the 2nd returns [1, 1] and the 3rd function call returns [1, 1, 1] but it's the 3rd function call return value only which is printed repeatedly.

Also, printing the same function return values as separate statements(as mentioned in that thread) gives expected result, i.e.,

>>> print(foo())
[1]
>>> print(foo())
[1, 1]
>>> print(foo())
[1, 1, 1]

So, why printing the same function return values together doesn't return the output the way it does when executed separately?

2
Your print(foo(), foo(), foo()) evaluates each foo() in turn, but the call to print() only occurs once all calls to foo() have finished. Also each return from foo() returns a reference to the same list. So print() just prints the same thing three times.quamrana
Functions actually return references to objects. In first variant, the print happens after all foo calls and print receives three references to the same list in the state after third "foo".Michael Butscher
I hate to refer you back to the link that inspired your experiment, but the reason it behaves this way in your test is the same as the reason why it behaves as it does for separate calls, and is explained in the effbot link given there: because the default value bound to the parameter is the same actual object each time. You see different results from different statements because that object has different contents each time; you see the same result multiple times when called in a single statement because you are looking at that same object multiple times after all the work.Karl Knechtel
Mandatory link to Ned Batchelderquamrana
If you do print(foo()) one at a time, it does output what you expect. I indeed suppose that in a combined print statement, all calls are executed first after which the list has value [1,1,1] which is then printed.Ronald

2 Answers

1
votes

What you didn't try in your second example is to save the return references like this:

a = foo()
print(a)
b = foo()
print(b)
c = foo()
print(c)

print(a, b, c)

Output:

[1]
[1, 1]
[1, 1, 1]
[1, 1, 1] [1, 1, 1] [1, 1, 1]

Now you should be able to see that a, b, c actually refer to the same list which has different contents at different times.

0
votes

the argument L is evaluated only once in the arg line, but by the time print function is executed the list is mutated to [1, 1, 1]. The most simple solution to prevent this is to copy/duplicate the list content each time.

print(foo()[:], foo()[:], foo())