Each variable gets a box. Small values, like numbers, booleans, or None, are written in a box.
Large values like strings or lists are written separately, with an arrow starting in the box that points to the value.
Each slot in a list is its own box that works the same way.
When you see an = sign, follow these steps:
Identify what is on the right-hand side:
If there's an expression on the right-hand side involving +, *, or another operator or function call, the result depends on the operation performed, and will usually be a newly-created object.
If the right-hand side just has a variable reference (possibly with indexing involved), then the result will be a copy of whatever is in the box that the right-hand expression identifies.
Identify which box is being updated based on the left-hand side.
If it's a variable, update that box.
If it involves indexing, figure out which box of which list is being updated.
Take the expression result and replace the contents of the box being updated with that value. Do not create any new arrows at this point unless the result you are using is an arrow (in that case, the new arrow points to the same place as the one you're copying).
Besides assignment using =, Specific methods like append, insert, and pop can change the contents of the object they apply to. += and related updating-assignments also change the value on their left-hand side.
Arrows cannot point to slots within lists. They can only point to strings or entire lists.
On a whiteboard, draw a memory diagram for the state at the end of this code:
num = 10
word = 'hello'
Check your answer below.
Draw the memory diagram for the the end of this code:
a = 10
b = 10
c = 'hello'
d = 'hello'
Check your answer below.
Note that it's also valid to draw a second arrow and 'hello' for 'b', but that's more work than just drawing an arrow to the 'hello' you already drew.
Note that it would also be valid to draw a second arrow in box 'd' that points to the same 'hello' you drew for 'c'. Becuase strings are immutable, it doesn't matter to the programmer whether they are aliases or clones, and Python often creates aliases instead of clones when it can.
Modify your partner's diagram to update it based on the following additional assignments:
b = d
c = a
Check your answer below.
Draw the memory diagram for the the end of this code:
x = 'A'
y = x + 'B'
Check your answer below.
Note that it's not valid to draw any arrows between x and y or between their values.
Now modify that based on these lines of code (Reminder: code executes one line at a time, using whatever variable values have been defined up to that point):
x = y
y = x
Check your answer below.
Note that when we assign 'x = y', the old value of x is thrown away, since no other variables reference it.
Now modify the diagram based on these additional lines of code:
x += 'C'
tmp = x
x = y
y = tmp
Check your answer below.
Here we used a third variable to help facilitate swapping x and y. Note that you don't have to draw the arrows crossed like this, but if you update things one-by-one, your arrows may end up this way unless you re-draw the strings 'ABC' and 'AB'. Putting 'ABC' below 'AB' avoids having to cross any arrows. The final value of x here is 'AB' and the final value of y (and also of tmp) is 'ABC'.
Draw the memory diagram for the the end of this code:
x = [11, 22]
y = x
z = list(x) # creates a clone
Check your answer below.
Now modify the diagram based on the following additional code that uses indexing and slicing:
x0 = x[0]
y1 = y[1]
zs = z[0:1]
Check your answer below.
Note that slicing creates a new list, and that indexing does NOT create new references when the items at the indices used are numbers. (If the thing in a slot being indexed slot is a reference, you'll get a copy of that reference).
Now add this variable to your diagram:
all = [x, y, z]
Check your answer below.
Draw the memory diagram for the the end of this code:
nums = [7, 23, 51]
alias = nums
clone = nums[:] # slice from start to end
Check your answer below.
Now modify that diagram based on the following additional code:
ext = clone + [96]
alias.append(121)
Check your answer below.
Next draw the diagram after these additional lines:
p = nums.pop(1)
clone.insert(0, 3)
nl = len(nums)
al = len(alias)
cl = len(clone)
el = len(ext)
Check your answer below.
Finally modify the diagram to account for this line (note: part of this line of code does NOT make sense):
alias = alias.append(239)
Check your answer below.
Note that append modifies the list you apply it to, but its result value is None. You should never write variable = variable.append(...) because this will replace the variable's value with None, which isn't useful. Just write variable.append(...) on its own instead, as we did in the second step for this example.
Note also that the number does in fact get appended to the list in question, which we can still see because alias was an alias of nums. Also note that the length of the nums list is now 4, and alias isn't a list any more, but the nl and al variables don't get updated: they hold the old length values computed previously.
Draw the memory diagram for the the end of this code:
x = [80, 75, 50]
y = x
z = [x, y[1]]
Check your answer below.
Now modify that to reflect the state after these two lines have been run:
x[0] = 100
y.append('hi')
Check your answer below.
Finally show what memory looks like after these two additional lines:
z.insert(1, x[1] + y[1])
removed = z[0].pop(1)
Check your answer below.
Draw the memory diagram for the the end of this code:
s = []
t = []
for i in range(3, 25, 7):
s.append(i)
Check your answer below.
Note that since t remains empty, it ends up as an empty box without any slots in it.
Now draw the memory diagram after these additional lines of code have run:
for i in range(3):
t.append(s[i])
Check your answer below.
This code copies the first three entries of s into t. Note how re-using i as the loop variable changes its value. Although not shown here, i changes value in every iteration of the loop.
Next, draw the memory diagram after these additional lines of code have run (note: these lines of code don't make a lot of sense):
for x in s:
x += 1
Check your answer below.
Note that values in s are unchanged: the loop copies those values into x, and then changes x. This code doesn't make sense because x gets overwritten in every iteration, and nothing else is changed. We could have just said x = s[-1] + 1 to set x equal to one more than the last element in s.
Next, draw the memory diagram after these additional lines of code have run (note: these lines of code don't make a lot of sense):
for i in range(len(s):
s[i] += 1
Check your answer below.
Here we actually modify the values in s within the loop, adding 1 to each value. That's because we're using indexing directly to set values within the loop.
Note that i also changes since we used it as our loop variable.
Finally, draw the memory diagram after these lines:
u = []
for x in t:
u.insert(0, x)
Check your answer below.
This code copies t in reverse order, since each new item it sees is farther along in t but is being added to the beginning of u. Note that x also gets overwritten.
Whew! Done with drawing memory diagrams. Now move onto the next part of the lab where you'll get practice writing code involving memory diagrams.