1.
a. ____
| |
v |
values ----> [0, | , 2]
The second entry in values is a reference to the list itself
b. [0, [...], 2]
c. [0, [...], 2]
d. [0, [...], 2]
e. This list is called "recursive" in that the list is defined with
respect to itself. Each time we ask for the entry at index 1, we
get the list itself. We could do this indefintely, e.g.:
>>> values[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]
2.
a. Say we type the following:
>>> x = [1, 2, 3]
>>> y = [4, 5, 6]
>>> list_swap1(x, y)
If we look at what's going on in memory when the function is first called:
x ----> [1, 2, 3]
y --------------> [4, 5, 6]
^ ^
list_swap1: | |
a -------- |
b ----------------
There are two list objects and x and y reference them. When the
function is called, a and b then also reference the same lists
respectively.
In the function list_swap1, changing the values of parameters a
and b will NOT change what the outer variables x and y reference.
b. This is another attempt at it, but when the function is called the
picture above will be the same. This time, we do full copies of a
and b using the slicing operation, however, this still will NOT
change the outer variables.
c. This is almost there. Now, instead of changing the values of a
and b, we are mutating/changing the list themselves. This will
swap the corresponding values, however, if a and b have different
lengths then either an error will occur or only some of the data
will get swapped.