Understanding Mutable and Immutable Objects in Python
Introduction
Python treats data as objects, from basic integers to complex lists. In this post, we’ll dive into the key differences between mutable and immutable objects, why these distinctions matter, and how Python’s handling of them can impact the way you write code. As a software engineering student, it’s essential to understand the efficiency and flexibility provided by these concepts, especially in complex applications.
id and type
Each object in Python has a unique identity (an id) and a type, which defines what kind of data it holds and its allowed operations. The id can be seen using id() and tells us the memory location of an object, while type() shows its data type. For instance:
pythona = 10
print(id(a), type(a)) # Outputs the id (memory location) and <class 'int'>Objects’ ids are useful in understanding how Python reuses or allocates memory based on whether an object is mutable or immutable.
Mutable Objects
Mutable objects, such as lists and dictionaries, can be modified after they are created. This means you can change, add, or remove items without creating a new object.
pythonlst = [1, 2, 3]
print(id(lst)) # Memory address before modification
lst.append(4)
print(id(lst)) # Same memory address after modificationIn the example, the id remains the same, showing that Python allows modifications to the original object itself.
Immutable Objects
Immutable objects, such as integers, strings, and tuples, cannot be changed once created. Any modification creates a new object in memory.
pythonnum = 10
print(id(num)) # Initial memory address
num += 1
print(id(num)) # New memory address after modificationThe id changes when num is modified, indicating that Python created a new object instead of altering the original.
Why It Matters: Mutable vs. Immutable in Python
The difference in Python’s treatment of mutable and immutable objects helps with memory management and performance. Immutable objects, being fixed, are often faster to access and require less memory management. Meanwhile, mutable objects, due to their flexibility, can be beneficial in data structures that require frequent changes.
Get Ntare GAMA Allan’s stories in your inbox
Join Medium for free to get updates from this writer.
Knowing this distinction helps us write efficient code. For example, we use tuples (immutable) when we need a fixed collection of items, while lists (mutable) are preferred when we plan to modify the collection frequently.
How Python Passes Arguments to Functions
In Python, arguments are passed by “assignment,” which behaves differently for mutable and immutable objects. Immutable objects are “copied” by reference, meaning any function using them doesn’t alter the original object. Mutable objects, however, can be modified within functions, affecting the original.
pythondef modify_item(item):
item.append(100) # This will affect the original list
lst = [1, 2, 3]
modify_item(lst)
print(lst) # Output: [1, 2, 3,100] - Original list is modifiedOn the other hand, with immutable types like integers:
pythondef modify_value(value):
value += 10
num = 5
modify_value(num)
print(num) # Output: 5 - Original value remains unchangedIn Python, assignment and referencing are related but have distinct meanings:
Assignment
- Assignment in Python means binding a variable to a specific object or value.
- For example, in `x = 5`, Python assigns the integer `5` to the variable `x`.
- After the assignment, `x` acts as a reference to the object `5`, but the object `5` itself remains unchanged by merely assigning it to `x`.
Referencing
- Referencing means pointing a variable to an existing object, not creating a new one.
- If `y = x`, `y` is now a reference to the same object `x` is referencing.
- No new copy of the object is created; `x` and `y` point to the same memory location. If the object they reference is mutable (like a list), changes to the object through one variable will be reflected in the other.
Example 1;
python
Assignment
x = [1, 2, 3] # x is assigned a list object [1, 2, 3]
Referencing
y = x # y references the same list that x does, no new list is created
Modifying the object through y
y.append(4) # Since x and y refer to the same list, changes through y affect x
print(x) # Output: [1, 2, 3, 4]
print(y) # Output: [1, 2, 3, 4]
In this example, `y = x` makes `y` a reference to the list object in `x`. Because they reference the same object, changes made to the list via `y` are also visible through `x`.
NSMALLPOSINTS and NSMALLNEGINTS
In Python’s internals, `NSMALLPOSINTS` and `NSMALLNEGINTS` are part of a caching mechanism used to optimize the handling of small integers. Here’s what they represent:
NSMALLPOSINTS (Number of Small Positive Integers)
- This refers to the range of small positive integers (typically `0` to `256`) that Python caches for efficiency.
- When you use a small integer in this range, Python doesn’t create a new integer object; instead, it reuses a pre-existing, cached object.
- For example, each instance of `x = 10` in Python doesn’t create a new integer object for `10` — it reuses the same, cached object, making it memory-efficient.
NSMALLNEGINTS (Number of Small Negative Integers)
- `NSMALLNEGINTS` serves the same purpose for small negative integers, though this range is generally limited and might be from `-5` to `-1`.
- Python doesn’t use as wide a range for negative integers as it does for positive integers in its caching mechanism.
Why These Exist
The caching of small integers allows Python to improve performance and memory usage, especially in loops or situations with frequent use of these integers. Since integers are immutable in Python, reusing the same object is safe and efficient.
In practice, this means small integer values are generally very efficient to work with in Python, while larger integers (outside the cached range) are still created as distinct objects when needed.
Conclusion
Understanding mutable and immutable objects is crucial in Python, as it affects memory use, code efficiency, and data integrity. By mastering these concepts, i was able to write code that is both optimal and functionally appropriate for different situations.







