I have two simple recursive functions in Python as follows:
def test_list(outcome=[1]):
outcome += [2*outcome[-1]]
print(outcome)
if outcome[-1] < 8:
test_list(outcome)
print(outcome)
def test_integer(n=1):
n *= 2
print(n)
if n < 8:
test_integer(n)
print(n)
2
4
8
8
4
2
Kowing the fact that subsequent doublings do not affect the value of the variable in the preceding recursions, I understand why the overall outcome of the function peaks at 8 and then drops to 2.
[1, 2]
[1, 2, 4]
[1, 2, 4, 8]
[1, 2, 4, 8]
[1, 2, 4]
[1, 2]
But in reality, it is:
[1, 2]
[1, 2, 4]
[1, 2, 4, 8]
[1, 2, 4, 8]
[1, 2, 4, 8]
[1, 2, 4, 8]
Any hints why these two functions behave differently?
Normally, an augmented assignment like x += y
is an alias for x = x + y
, which creates a new value and binds it with the left argument.
However, the list class redefines +=
in a special way, so that it directly mutates the left argument instead of assigning to it. If you want the new value semantics, you have to use the plain assignment outcome = outcome + ...
.
Illustration:
old_a = a = [1, 2]
a += [99] # <- mutation
print(old_a, a) # [1, 2, 99] [1, 2, 99]
old_b = b = [1, 2]
b = b + [99] # <- new value
print(old_b, b) # [1, 2] [1, 2, 99]