Skip to content

Exercises — Interning

Exercise 1🟢 Beginner Predict the output of the following code before running it. Think carefully about the integer cache boundaries:

a = 0
b = 0
print(a is b) # ?
a = 256
b = 256
print(a is b) # ?
a = 257
b = 257
print(a is b) # ?
a = -5
b = -5
print(a is b) # ?
a = -6
b = -6
print(a is b) # ?

Exercise 2🟢 Beginner Predict the output and explain why the results differ:

a = 100
b = 100
c = a + 0 # arithmetic result — is it interned?
print(a is b) # ?
print(a is c) # ?
print(b is c) # ?
print(a == b == c) # ?

Exercise 3🟡 Intermediate Predict the output and explain each result:

# loop counter — inside cache range
total = 0
for i in range(5):
total += i
print(i is 4) # ? — is the loop variable interned?
print(i == 4) # ?
# arithmetic result outside cache range
x = 200
y = 100
z = x + y # 300 — outside cache range
print(z is 300) # ?
print(z == 300) # ?

Exercise 4🟢 Beginner Predict the output of the following code. Think about which strings look like identifiers:

a = "hello"
b = "hello"
print(a is b) # ?
a = "hello_world"
b = "hello_world"
print(a is b) # ?
a = "hello world" # contains space
b = "hello world"
print(a is b) # ?
a = "hello!" # contains punctuation
b = "hello!"
print(a is b) # ?
a = "123abc" # starts with digit
b = "123abc"
print(a is b) # ?

Exercise 5🟡 Intermediate Predict the output and explain why string concatenation affects interning:

a = "hello"
b = "world"
c = "helloworld"
d = a + b # runtime concatenation — is it interned?
print(c is d) # ?
print(c == d) # ?
# now with interning
import sys
e = sys.intern(a + b)
f = sys.intern("helloworld")
print(e is f) # ?
print(e == f) # ?

Exercise 6🟡 Intermediate Predict the output and explain the difference between compile-time and runtime strings:

# compile time — Python can intern these
a = "user_id"
b = "user_id"
print(a is b) # ?
# runtime — built dynamically
prefix = "user"
suffix = "_id"
c = prefix + suffix # built at runtime
print(a is c) # ?
print(a == c) # ?
# forced interning
import sys
d = sys.intern(prefix + suffix)
print(a is d) # ?

Exercise 7🟢 Beginner Use sys.intern() to ensure these long strings are shared, then verify with is:

import sys
long_key = "this_is_a_very_long_dictionary_key"
# without interning
a = "this_is_a_very_long_dictionary_key"
b = "this_is_a_very_long_dictionary_key"
print(a is b) # ?
# with interning
a = sys.intern("this_is_a_very_long_dictionary_key")
b = sys.intern("this_is_a_very_long_dictionary_key")
print(a is b) # ?

Exercise 8🟡 Intermediate Rewrite this code to use interned keys and verify all dicts share the same key objects:

# ❌ without interning — 3000 separate key objects
users = [
{"user_id": i, "user_name": f"user_{i}", "user_email": f"user_{i}@example.com"}
for i in range(1000)
]
# ✅ rewrite using sys.intern() so all 1000 dicts
# share the same 3 key objects
# verify:
# list(users[0].keys())[0] is list(users[999].keys())[0] → True
# list(users[0].keys())[1] is list(users[999].keys())[1] → True
# list(users[0].keys())[2] is list(users[999].keys())[2] → True

Exercise 9🔴 Advanced Measure the memory difference between interned and non-interned dictionary keys using sys.getsizeof():

import sys
# build two versions of the same dataset
# one with interned keys, one without
# expected:
# non_interned_size → larger
# interned_size → smaller
# hint: use sys.getsizeof() to measure
# note: sys.getsizeof() measures the object itself,
# not the objects it references —
# think about how to measure the total size

Exercise 10🟢 Beginner Fix this code that incorrectly uses is to compare values:

# ❌ unreliable — using is for value comparison
def is_valid_status(status):
return status is "active" # wrong!
print(is_valid_status("active")) # may be True or False — unreliable
# ✅ fix it so it works correctly regardless of interning

Exercise 11🟡 Intermediate Identify all the incorrect uses of is in this code and fix them:

def process_user(user):
# ❌ incorrect uses of is
if user["status"] is "active": # wrong
print("user is active")
if user["age"] is 18: # wrong
print("user just turned 18")
if user["name"] is "Alice": # wrong
print("hello Alice")
if user["score"] is None: # ? — is this one correct?
print("no score yet")
if user["verified"] is True: # ? — is this one correct?
print("user is verified")

Exercise 12🔴 Advanced This code uses is for dictionary key lookup optimisation. Identify what is correct, what is wrong, and rewrite it properly:

import sys
# intern the keys
STATUS_KEY = sys.intern("status")
NAME_KEY = sys.intern("name")
AGE_KEY = sys.intern("age")
users = [
{STATUS_KEY: "active", NAME_KEY: "Alice", AGE_KEY: 30},
{STATUS_KEY: "inactive", NAME_KEY: "Bob", AGE_KEY: 25},
]
# ❌ incorrect — mixing is and == incorrectly
for user in users:
if list(user.keys())[0] is STATUS_KEY: # is this correct?
if user[STATUS_KEY] is "active": # is this correct?
print(f"{user[NAME_KEY]} is active")
if user[AGE_KEY] is 30: # is this correct?
print(f"{user[NAME_KEY]} is 30")
# Questions:
# 1. Which uses of is are correct and which are wrong?
# 2. Fix all incorrect uses
# 3. Which comparisons benefit from interning and which do not?

Try predicting every result before running the code — the goal is to build a precise mental model of when Python reuses objects and when it does not, so you never accidentally rely on interning for correctness.