Python default values are evaluated only once

Question:

I’m getting some inconsistencies with how this work. In the tutorial, the example clearly demonstrates that the list is passed by reference, so any changes to the list within the function is reflected in the original value after the function ends.

def fun1(a,L=[]):
    L.append(a)
    return L

print fun1(1)
print fun1(2)
print fun1(3)

[1]
[1, 2]
[1, 2, 3]

If I try THIS example, however, why does b not change (i.e. if b is stored as "2", then it should return 3)?

def g(a, b=1):
    b=a+b
    return b

>>> g(1)
    2
>>> g(1)
    2

I’m going to guess that it’s because the statement b = a+b assigns b to a new b that is only accessible within the function environment, but isn’t this inconsistent with how the first example works (in which it’s obvious that the variable L was defined BEFORE the function starts, and also can be altered within the function itself).

Asked By: Mezzoforte

||

Answers:

Because b is immutable when you try to assign a new value it doesn’t change the existing value, it reassigns the variable to a new number object.

Answered By: Mark Ransom

It’s because assignments with operator = do not changes the underlying objects, but instead assigns a python object to a new variable name (possibly overwriting or overshadowing it).

You can have the same behaviour with lists if you use the operator = instead of .append():

>>> def g2(a, b=[]):
...   b = b + [a]
...   return b
...
>>> g2(1)
[1]
>>> g2(4)
[4]
>>> g2(5)
[5]

See how b is always a list of length 1? That’s because I locally reassign b inside the scope of the function and that assignment will go away when I leave the function, so when I enter it again, it re-uses the global empty list, which was not modified, as default value. When you use append you modify the underlying python object in-place. When I use =, I assign a new local variable to the result of the expression (which in the case of b + [a] is a brand new python object).

Last point, some python objects such as numbers or strings are immutable. That is, unlike list, the allocated python object in memory cannot change. So the only way to manipulate them is to create new object that can be assigned using operator =. Thus, there no real way to modify such a variable the caller passed along in a way that impacts the caller as well.

Answered By: Lærne
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.