Mastering Python Variables and Memory
Object References
Labels, Not Boxes
In many programming languages, variables are often described as boxes or containers where you store data. In Python, it's more accurate to think of variables as labels or name tags that you attach to objects. The variable isn't the box; it's a pointer to the box.
When you write x = 100, you're not putting the number 100 inside a container called x. Instead, Python creates an integer object with the value 100 somewhere in memory, and then attaches the label x to that object.
Python's variables aren't buckets that contain things; they're pointers that reference objects.
This might seem like a small distinction, but it's fundamental to understanding Python's behaviour. This "everything is an object" philosophy applies to numbers, strings, lists, and even functions. Each piece of data is an object residing at a specific memory address.
Finding an Object's Address
Since every object lives at a unique location in memory, Python provides a way to find its address. The built-in id() function returns a unique integer that represents the object's identity for its lifetime. Think of it as the object's social security number or memory address.
# Create a string object
salutation = "Hello"
# Get its unique ID
print(id(salutation))
# Output might be something like: 140232757237360
The exact number you see will change every time you run the code, as it depends on where your computer decides to store the object at that moment. What's important is that the ID is unique to that specific object.
Now, what happens if we assign another variable to salutation? Are we creating a copy?
salutation = "Hello"
greeting = salutation
# Check the IDs
print(f"ID of salutation: {id(salutation)}")
print(f"ID of greeting: {id(greeting)}")
# Both will print the exact same ID!
No copy is made. Instead, we've just attached a second label, greeting, to the very same string object that salutation points to. Both variables reference one object in memory.
Identity vs. Equality
This leads to a crucial distinction in Python: checking if two variables are equal versus checking if they are the same object.
- The
==operator checks for equality. It asks, "Do these two objects have the same value?" - The
isoperator checks for identity. It asks, "Do these two variables point to the exact same object in memory?"
Let's see this with lists. Lists are mutable, meaning their contents can change. This makes the distinction between identity and equality very clear.
list_a = [1, 2, 3]
list_b = [1, 2, 3] # A new list with the same values
list_c = list_a # A new label for the first list
# Check equality (==)
print(f"list_a == list_b: {list_a == list_b}") # True
print(f"list_a == list_c: {list_a == list_c}") # True
# Check identity (is)
print(f"list_a is list_b: {list_a is list_b}") # False
print(f"list_a is list_c: {list_a is list_c}") # True
# Let's verify with id()
print(f"ID of list_a: {id(list_a)}")
print(f"ID of list_b: {id(list_b)}") # Different ID
print(f"ID of list_c: {id(list_c)}") # Same ID as list_a
list_aandlist_bare two different objects that happen to hold the same values.list_aandlist_care two different names for the exact same object.
Because list_a and list_c point to the same object, changing the object through one variable affects the other. This is a common source of bugs for new Python programmers.
# Modify the list using the 'list_c' label
list_c.append(4)
# Print the list using the 'list_a' label
print(list_a)
# Output: [1, 2, 3, 4]
Understanding that variables are just references to objects is key to managing data and avoiding unintended side effects in your programs.
Time to test your knowledge of these core concepts.
In Python, what is the most accurate way to describe a variable?
What is the primary difference between the == and is operators in Python?
This grasp of Python's memory model will be invaluable as you start working with more complex data structures and functions.