The function f1
creates a whole new list, then uses that new list in a second call to f1
. The function f2
only ever passes the original list to its calls to f2
.
To expand, in f1
, the logic looks like this:
def f1(l1=[],num = 2):
if num == 0: return[1]
print('b',num,l1)
# Here, *f1(l1, num-1) uses the original value of
# l1, then expands it.
# *l1 expands the original value of l1.
# The [...] creates a completely new list,
# and finally, l1 = ... assigns that completely new
# list to the value of l1.
l1 = [*l1, *f1(l1, num-1)]
# Here, the l1 in *f1(l1, num -1) refers to the
# result of the assignment above, l1 = ...
#
# *l1 also refers to the result of the assignment
# above.
#
# Again, [...] creates a completely new list,
# then l1 = ... assigns that new list to the name l1.
l1 = [*l1, *f1(l1, num -1)]
print('a',num,l1)
return l1
# This function is identical
def f1(first_list = [], num = 2):
if num == 0: return [1]
print('b', num, first_list)
second_list = [*first_list, *f1(first_list, num - 1)]
third_list = [*second_list, *f1(second_list, num - 1)]
print('a', num, third_list)
return third_list
In f2
, the logic looks like this:
def f2(l1=[],num = 2):
if num == 0: return[1]
print('b',num,l1)
# Here, both *f2(l1, num-1) calls refer to the original l1
# passed in the argument list.
#
# *l1 refers to the original l1 passed in the argument list,
# too.
#
# The [...] creates a whole new list,
# then l1 = ... assigns that new list to the name l1.
l1 = [*l1, *f2(l1, num-1),*f2(l1, num -1)]
print('a',num,l1)
return l1
# This function is identical
def f2(first_list = [], num = 2):
if num == 0: return [1]
print('b', num, first_list)
second_list = [*first_list, *f2(first_list, n - 1), *f2(first_list, n - 1)]
print('a', num, second_list)
return second_list
The difference between f2
and f3
is, in f2
, you are not calling any code which modifies the list: you are creating a whole new list, then re-assigning the name l1
to refer to the new list. In f3
, you are not creating a whole new list, you are just modifying the list in-place.
Lets take a simplified example that demonstrates this:
>>> def set_value(first_list):
... first_list = [ 2 ]
...
>>> mylist = [3, 4]
>>> set_value(mylist)
>>> mylist
[3, 4]
>>>
>>> def set_value(first_list):
... first_list.clear()
... first_list.append(2)
...
>>> mylist
[3, 4]
>>> set_value(mylist)
>>> mylist
[2]
>>>
The +=
operator modifies the list on the left, while the =
doesn't modify the list at all. l1 += ...
adds ...
to the end of the the list l1
refers to. l1 = ...
just changes what the name l1
refers to: you could make it refer to an integer, or a dictionary, or an object, or anything else.