1. Python Memory Model

Introduction

Data

Three components:

  1. id: unique identifier, often a memory address
print(id(3))
print(id("words"))
  1. type: determines what functions can operate on it
print(type(3))
print(type('words'))
  1. value: accessing the value is known as evaluating an object

Variable

Not an object so does not store data. Stores id that refers to an object that stores data. Variables do not have a type. Essentially means "go to this id".

Mutability and Aliasing

Strings are immutable, so will change the object it references

prof = 'Diane'
print(id(prof))
prof = prof + 'Horton'
print(id(prof))

For immutable objects we make sure to draw a double box

Mutable objects will keep the same ID.


x = [1, 2, 3]
print(id(x))
x[0] = 10000
print(id(x))
x.extend([4, 5, 6])
print(id(x))

Aliasing is when two variables point to the same object

x = [1, 2, 3]
y = [1, 2, 3]
z = x

print(id(x),id(y),id(z))

Modifying the mutable object referenced by z will modify x which is a side-effect of aliasing

Equality

Value equality == checks if the values stored in the objects are equal

Identity Equality is checks if the ids of the objects are the same for the objects that they reference.

Functions and Parameters


# Example 1.

def mess_about(n: int, s: str) -> None:
	message = s * n 
	print (message)

if __name__ == '__main__':

	count = 13
	word = 'nonsense'
	mess_about (count, word)

Each variable in the parentheses is a parameter, and when we call the function, each expression in the parentheses is an argument.

Python Types: Mutable vs Immutable

Type Mutable? Examples Notes
int No 1, 42, -7 New object created on change
float No 3.14, -2.0 Same behavior as int
bool No True, False Subclass of int
str No "hello", 'world' Strings are immutable
tuple No (1, 2), ("a", [1, 2]) May contain mutable elements
frozenset No frozenset([1, 2, 3]) Immutable version of set
bytes No b'abc' Immutable byte sequence
list Yes [1, 2, 3], [] Can append, pop, modify elements
dict Yes {"a": 1}, {} Keys must be immutable
set Yes {1, 2, 3}, set() Unordered, no duplicates
bytearray Yes bytearray(b"abc") Mutable version of bytes
defaultdict, OrderedDict Yes From collections module Mutable dictionaries with extra functionality
DataFrame, Series (Pandas) Yes df['col'] = ... Changes propagate in place — use caution

Tracking function calls

Stack Frame: stores information of the function that is currently running and any variables defined inside of it.

Every time we call a function, the following happens:

  1. A new frame is created and placed on top of any frames that may already exist. We call this pile of frames the call stack.
  2. Each parameter is defined inside that frame.
  3. The arguments in the function call are evaluated in order from left to right. Each is an expression, and evaluating it yields the id of an object. Each of these ids is assigned to the corresponding parameter.

Based on our previous example before printing message:

![|270](/img/user/Introduction to CS/attachments/Pasted image 20250109154115.webp)

If the variable on the left-hand-side of the assignment doesn’t already exist in the top stack frame, Python will create it in that top stack frame. Here message is a local variable.

When a function returns, the frame for that call and its variables are deleted.

Passing an argument creates an alias

If an argument is a variable, we assign the ID of the object it references to the function's parameter. If it's mutable, we have to worry about side effects.