Skip to main content

Practice 10 — Variable Scoping and Mutable Data

Skills: 5, 9​

Variable Scoping and Mutable Data​

The "program directory" is our mental model of how a language keeps track of variable names and their associated values. In Python, assignment = both creates and updates variables.

Since the examples below use global and nonlocal, and give local variables the same names as global ones, use #level advanced for them.

Variable Scoping​

Global vs Local Bindings​

Example 1: Global Assignment

score = 100 # score is bound in the global directory

def show_score():
return score

print(show_score()) # prints 100

The function show_score looks up score in the global directory.

Example 2: Local Binding and Shadowing

score = 100

def change_score():
score = 50 # creates NEW local variable, doesn't change global
return score

print(change_score()) # prints 50
print(score) # prints 100 -- global unchanged

Using Global and Nonlocal​

Example 3: Actually Updating Global

score = 100

def update_global_score():
global score # explicitly refer to global variable
score = 75

update_global_score()
print(score) # prints 75

Example 4: Nested Functions

def outer():
count = 10
def inner():
nonlocal count # refer to count from outer function
count = count + 5
inner()
return count

print(outer()) # prints 15

Exercise 1: Variable Scoping​

What will be printed by each of these code blocks?

x = 5

def func1():
x = 10
return x

def func2():
global x
x = 15
return x

print(func1()) # What prints here?
print(x) # What prints here?
print(func2()) # What prints here?
print(x) # What prints here?

Memory Model​

We expand our program directory model to include a "heap" -- where mutable structured data lives.

Mental Model:

  • Program Directory: Maps names to values (or addresses for structured data)
  • Heap: Stores structured data objects with unique addresses

Example:

  • Directory: book1 -> @1001
  • Heap: @1001: LibraryBook("Python Guide", 3)

Student Record Example​

Data Design​

Each student has an ID, name, and current credit hours. We want to update credits when they register for courses.

from dataclasses import dataclass

@dataclass
class StudentRecord:
id: int
name: str
credits: int

student1 = StudentRecord(12345, "Alice Smith", 15)

student1.credits = student1.credits + 3 # registered for 3-credit course
print(student1.credits) # prints 18

Python doesn't require special syntax -- all fields are mutable by default.

Exercise 2: Student Records​

Create a data definition for a Course with fields for enrollment count and current grade average. Then create a course instance and update its enrollment.

Aliasing and the Heap​

Aliasing occurs when two names refer to the same object (same heap address).

Example:

student1 = StudentRecord(12345, "Alice Smith", 15)
student2 = student1 # aliasing -- both refer to same object

student1.credits = student1.credits + 3
print(student2.credits) # prints 18

Program Directory/Heap Visualization:

Directory:
student1 → @1001
student2 → @1001 # Same address

Heap:
@1001: StudentRecord(12345, "Alice Smith", 18)

Exercise 3: Aliasing Effects​

What will be the final values of a, b, and c after this code runs?

from dataclasses import dataclass

@dataclass
class Point:
x: int
y: int

a = Point(1, 2)
b = a
c = Point(1, 2)

a.x = 5
b.y = 10

Equality: Structural vs Reference​

Two Types of Equality​

Structural Equality: Same contents in all fields Reference Equality: Same object in memory (same heap address)

Examples with Student Records​

alice1 = StudentRecord(100, "Alice", 15)
alice2 = StudentRecord(100, "Alice", 15) # same content, different object
alice3 = alice1 # alias

# Structural equality (==)
print(alice1 == alice2) # True -- same contents
print(alice1 == alice3) # True -- same contents

# Reference equality (is)
print(alice1 is alice2) # False -- different objects
print(alice1 is alice3) # True -- same object (alias)

Mutation Effects on Equality​

alice1.credits = 18 # update through one alias

print(alice1 == alice2) # now False -- different contents
print(alice1 is alice3) # still True -- same object
print(alice1.credits == alice3.credits) # True -- both show 18

Exercise 4: Equality and Mutation​

What will each of these print statements output?

from dataclasses import dataclass

@dataclass
class Box:
contents: str

box1 = Box("apple")
box2 = Box("apple")
box3 = box1

print(box1 == box2) # True or False?
print(box1 is box2) # True or False?
print(box1 is box3) # True or False?

box1.contents = "orange"

print(box1 == box2) # True or False?
print(box1 is box3) # True or False?
print(box3.contents) # What value?

Wrap-Up​

Why is understanding aliasing important when working with mutable data?