This is actually a bit complex and requires two explanations.
First, a python function argument act as label on the passed object. For example, in the following code, arg
is the local label (/name) attached to the initial list. When the label arg
is re-used, for example by attaching it to a new object (17
), the original list is not reachable anymore within function f
.
On the other hand, outside of f
, the list labeled L
is still here, untouched:
def f(arg):
arg = 17
print(arg) # 17
L = ['a', 'list']
f(L)
print(L) # ['a', 'list']
That explains why the following function doesn't reverse your list in place:
def reverse_list(arg):
arg = arg[::-1]
print(arg) # ['list', 'a']
L = ['a', 'list']
reverse_list(L)
print(L) # ['a', 'list']
This function simply attach the label arg
to a new list (that is indeed equal to the reversed list).
Secondly, the difference between arg[:] = ...
and arg = ...
is that the first will modify the content of the list (instead of attaching the label arg
to a new object). This is the reason why the following works as expected:
def alt_reverse_list(arg):
arg[:] = arg[::-1]
L = ['a', 'list']
alt_reverse_list(L)
print(L) # ['list', 'a']
In this second example we say that the list has been mutated (modified in place). Here is a detailed explanation on slice assignments
For the same reason, calling arg.reverse()
would have worked.
Identifying objects
Using the id() function can help figure out what is going on with the argument in the first example (where we don't mutate the list but affect a new value):
def reverse_list(arg):
print("List ID before: ", id(arg))
arg = arg[::-1]
print("List ID after: ", id(arg))
L = ['a', 'list']
print("Original list ID: ", id(L))
reverse_list(L)
print("Final list ID: ", id(L))
Which will print something like:
Original list ID: 140395368281088
List ID before: 140395368281088
List ID after: 140395368280447 <--- intruder spotted
Final list ID: 140395368281088
Here we can clearly see that after calling arg = arg[::-1]
the object we are manipulating under the name arg
is not the same. This shows why the function doesn't have any (side) effect.