13. References
It is important for us to have an idea of what exactly is stored in our variables
Warning
The ideas below are presented at a very high level and are not quite entirely correct for Python and other similar programming languages. The differences come up in the nuances, but the following is sufficient to cover the important ideas that you need to know. In fact, where there are differences between the following and how Python actually works is not overly important for us, especially in introductory computer science.
Note
We typically use hexadecimal (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F) when referring to memory addresses, but for simplicity, we will use decimal numbers throughout this topic.
Here is an idealized view of memory inside a computer
13.1. Primitive Types in Memory
Let’s say we have a single integer called
x
An integer is a primitive type
In many programming languages integers take up 32 bits worth of memory
That means 32
0
s and1
sE.g.
00101010010010110101110100010100
, which is the number709582100
Since we know how much memory an integer takes up, we can easily put integers into nicely divvied up chunks of memory
If we divided memory into blocks of 32 bits
And we create an integer variable
x = 17
Something like this will happen
The value
17
gets assigned to one of the 32 bit sections of memoryA label
x
is created for that location
If we wanted to copy the value of
x
into another variable, I could write something likey = x
When this happens
Copy the contents from the location with the label
x
Place the copied value into another 32 bit section of memory
Create a label
y
for the copied value’s location
The contents of
x
are copied toy
This strategy works great for types that have a nicely defined sizes
But what happens when we do not know beforehand how much memory something needs in order to store it?
13.2. Lists in Memory
Above is a list with length
8
The contents are labeled
a
–h
, but these are arbitrary labels and we can think of them as integersIn the examples so far, memory was divided into chunks of 32 bits which is perfect for integers
Unfortunately, we need to store a whole list that contains 8 integers
This needs 256 bits
Fortunately we have a solution
Store each of the elements within the list in their own memory location
Similar to how the integer
17
was stored above
Section off a large block of memory for the list to hold references to each of the elements of the list
For simplicity, instead of storing references within the list, we will pretend that the contents of the list are stored within the block of memory sectioned off for the list
For example, the following image shows how we can think of storing the list
[a, b, c, d, e, f, g, h]
Just put each integer into its own memory location
Again, in reality we actually store a reference to the integers, but we are ignoring this for now
Keep track of the fact that our list starts at memory address 677 and goes to 684
The trick is in how this is managed
13.2.1. References
1z = [a, b, c, d, e, f, g, h]
Given the above list creation, the computer finds a contiguous block of memory to store the contents of the list
Each element in the list fits nicely into the divvied up sections
Then, the information needed to find and access the list contents is stored in a piece of memory labelled with the variable
z
The list is not stored in
z
; the location of the list in memory is stored inz
Activity
Take a moment to look at this image and see if you can explain why we start counting at 0 when indexing lists.
If we wanted to make a copy of
z
like we did with the integersx
andy
, we could write something likew = z
And just like with the integers, this copies the contents of the memory location of
z
and puts it into a new location labelled with aw
However, the catch is that the contents of
z
is the memory address of the listAfter making the copy into
w
, how many references do have that get me to the memory location of the list?
If I want to make a change to
w
and I write something likew[4] = P
, the computer goes to the list referenced byw
and alters the value at index4
This does not alter the contents of the memory location of
w
; this alters the data at the memory location that is referenced to byw
In fact, this also alters the data at the memory location that is referenced by
z
What would happen if I wrote
print(z[4])
?
When we have two or more references referring to the same thing in memory, we call these aliases
w
is an alias forz
This is discussed further in the following topic
Note
As mentioned earlier, in reality Python would not actually store the contents of the list within the block of memory allocated for the list. Instead, Python stores the contents in their own memory locations and the list stores references to the contents.
13.3. For Next Class
If you have not already, read Chapter 14 of the text
If you have not already, read Chapter 15 of the text (only lightly though)