If you pass an immutable value, changes to it do not change its value in the caller - because you are
rebinding the name to a new object. This is because there is no way of mutating an immutable object.
If you pass a mutable value, changes made in the called function, also change the value in the
caller, so long as you do not rebind that name to a new object.
If you assign the name to a new value, that change and subsequent changes to the name
are not seen in the caller.
So if you pass a list, and change its 0th value, that change is seen in both the called and the
caller.
But if you reassign the name to a new list, this change is lost.
But if you slice the list and replace that with a new list, that change is seen in both the called
and the caller.
EG:
def change_it(list_):
# This change would be seen in the caller if we left it alone
list_[0] = 28
# This change is also seen in the caller, and replaces the above
# change
list_[:] = [1, 2]
# This change is not seen in the caller.
# If this were pass by reference, this change too would be seen in
# caller.
list_ = [3, 4]
thing = [10, 20]
change_it(thing)
# here, thing is [1, 2]
If you're a C fan, you can think of this as passing a pointer by value - not a pointer to a pointer to a
value, just a pointer to a value. And sometimes the thing you are pointing at is const, and sometimes it is not.