Understanding Python Objects: Mutability, Copying, and Garbage Collection
Written on
Chapter 1: Introduction to Python Objects
In any object-oriented programming (OOP) language, objects serve as fundamental components. Each language has its own syntax for creating, modifying, and deleting these objects. In Python, every object possesses an identity, a type, and a value, with only the value subject to change over time. This article will cover several key topics: what variables are in Python, the distinctions between shallow and deep copies of objects, and the concept of Python's garbage collection.
For those interested in staying updated with my latest articles or joining a community of fellow developers, consider following me on Medium. Your support means a lot! ❤️
Section 1.1: Understanding Variables in Python
Often, variables are visualized as containers or boxes, which can complicate the understanding of reference variables in OOP languages. In Python, variables function similarly to reference variables in Java; they can be thought of as labels attached to objects.
var_one = [1, 2, 3]
var_two = var_one
var_one.append(4)
print(var_two) # Output: [1, 2, 3, 4]
In this example, modifying the list referenced by var_one by appending an item also reflects in var_two, demonstrating that both variables point to the same list. Multiple labels can reference a single object, leading us to ponder how to determine if two objects are identical.
To check if two objects are the same, you can use the id() function, which returns a unique identifier representing the memory address of an object. If two variables reference the same object, they will share the same ID.
charles = {'name': 'Charles L. Dodgson', 'born': 1832}
lewis = charles
print(lewis is charles) # Output: True
print(id(charles), id(lewis)) # Both IDs are the same
When lewis is modified, it affects charles as they are bound to the same object. In contrast, a new object with the same values will have a different ID.
alex = {'name': 'Charles L. Dodgson', 'born': 1832, 'balance': 950}
print(alex == charles) # Output: True
print(alex is not charles) # Output: False
The is and is not operators check for object identity, while == compares the values contained within the objects. The is operator generally performs faster as it cannot be overloaded, unlike the == operator, which most built-in types and Python objects override using the __eq__ special method.
Section 1.2: Shallow Copy vs Deep Copy
Shallow copies are straightforward to create but may not always be desirable. A shallow copy only duplicates references to the existing objects instead of creating new ones. This approach conserves memory but can lead to unexpected behavior with mutable items.
list_1 = [3, [66, 55, 44], (7, 8, 9)]
list_2 = list(list_1)
This means that changes made to embedded mutable objects will affect all references to those objects.
list_1.append(100)
list_1[1].remove(55)
print('list_1:', list_1) # Output: [3, [66, 44], (7, 8, 9), 100]
print('list_2:', list_2) # Output: [3, [66, 44], (7, 8, 9)]
In the above example, modifying list_1 also alters list_2 due to shared references.
To avoid these issues, deep copies create entirely new references for all embedded objects. Python's standard library includes a module that provides two functions: copy() for shallow copies and deepcopy() for deep copies.
import copy
class Bus:
def __init__(self, passengers=None):
if passengers is None:
self.passengers = []else:
self.passengers = list(passengers)
def pick(self, name):
self.passengers.append(name)
def drop(self, name):
self.passengers.remove(name)
bus1 = Bus(['Alice', 'Bill', 'Claire', 'David'])
bus2 = copy.copy(bus1)
bus3 = copy.deepcopy(bus1)
print(id(bus1), id(bus2), id(bus3)) # Different IDs
Manipulating a deep copy will not affect the original object, ensuring complete independence.
Section 1.3: Garbage Collection in Python
Unlike languages such as C# where objects are explicitly destroyed, Python employs garbage collection to reclaim memory from objects that are no longer reachable. The del statement can remove references, but it does not delete the objects themselves.
a = [1, 2]
b = a
del a
print(b) # Output: [1, 2]
Once a is deleted, the original object becomes eligible for garbage collection if no other references exist.
The first video, "Immutable vs Mutable Objects in Python," provides an insightful overview of these concepts and their implications in programming.
The second video, "Python: Mutable vs Immutable objects," further elaborates on the differences and offers practical examples.
Further Reading
- Chapter 6 of "Fluent Python"
- The official Python documentation on the copy module
- The "Data Model" chapter in "The Python Language Reference"