Why Everything Is an Object in Python: Understanding Mutable vs Immutable
This article explains Python’s core principle that every value is an object, detailing how identity, type, and value define objects, and contrasts mutable and immutable types through practical code examples, illustrating their impact on memory management, variable assignment, function arguments, and common pitfalls.
When I started learning Python I was surprised by the statement “everything is an object”. In Python every value has three attributes: an identity (its memory address), a type, and a value. The built‑in functions id() and type() reveal the first two.
<code>a = 42
b = "Hello, Python!"
c = [1, 2, 3]
print(f"a: id={id(a)}, type={type(a)}")
print(f"b: id={id(b)}, type={type(b)}")
print(f"c: id={id(c)}, type={type(c)}")
</code>Running the code shows that each object has a distinct id and a type such as int , str , or list . The operator is compares identities, while == compares values.
<code>a = [1, 2, 3]
b = [1, 2, 3]
c = a
print(f"a == b: {a == b}") # True, values are equal
print(f"a is b: {a is b}") # False, different objects
print(f"a is c: {a is c}") # True, same object
</code>Mutable Objects
A mutable object can change its value without changing its identity. Lists, dictionaries and sets are examples.
<code>my_list = [1, 2, 3]
print(f"Original list: {my_list}, id={id(my_list)}")
my_list.append(4)
print(f"After append: {my_list}, id={id(my_list)}")
list_copy = my_list
list_copy.append(5)
print(f"Original after modifying copy: {my_list}, id={id(my_list)}")
print(f"Copy: {list_copy}, id={id(list_copy)}")
</code>The output demonstrates that the list’s id stays the same while its contents change, and every reference sees the modification.
Immutable Objects
Immutable objects cannot be altered after creation. Integers, floats, strings and tuples belong to this group.
<code>s = "hello"
print(f"Original string: {s}, id={id(s)}")
s = s + " world"
print(f"After concatenation: {s}, id={id(s)}")
a = 42
b = 42
print(f"a: {a}, id={id(a)}")
print(f"b: {b}, id={id(b)}")
str1 = "Python"
str2 = "Python"
print(f"str1 is str2: {str1 is str2}")
</code>Appending to a string creates a new object with a new id . Small integers and short strings are cached, so identical literals may share the same object.
Why Mutability Matters: Python’s Different Handling
1. Assignment behavior
<code>x = 10
y = x
x = 20
print(f"x: {x}, y: {y}")
list_a = [1, 2, 3]
list_b = list_a
list_a[0] = 99
print(f"list_a: {list_a}, list_b: {list_b}")
</code>Rebinding an immutable variable creates a new object, while mutating a mutable object affects all references.
2. Performance considerations
Immutable objects are predictable, thread‑safe and can be used as dictionary keys.
<code>tuple_key = (1, 2)
list_value = [3, 4]
dict_example = {tuple_key: "Example with tuple key"}
print(dict_example)
try:
dict_example = {list_value: "This will fail"}
except TypeError as e:
print(f"Error: {e}")
</code>3. Memory management and efficiency
Because immutable objects never change, Python can reuse them, saving memory. Examples include the small‑integer cache (‑5 to 256) and string interning.
<code>a = 256
b = 256
print(f"a is b (small integers): {a is b}")
c = 257
d = 257
print(f"c is d (larger integers): {c is d}")
s1 = "python"
s2 = "python"
print(f"s1 is s2: {s1 is s2}")
</code>Passing Arguments to Functions
Function arguments are passed by object reference. The effect differs for mutable and immutable objects.
<code>def modify_immutable(n):
n += 1
print(f"Inside function: n = {n}, id={id(n)}")
num = 10
print(f"Before function call: num = {num}, id={id(num)}")
modify_immutable(num)
print(f"After function call: num = {num}, id={id(num)}")
</code> <code>def modify_mutable(lst):
lst.append(4)
print(f"Inside function: lst = {lst}, id={id(lst)}")
my_list = [1, 2, 3]
print(f"Before function call: my_list = {my_list}, id={id(my_list)}")
modify_mutable(my_list)
print(f"After function call: my_list = {my_list}, id={id(my_list)}")
</code>To avoid unintended changes, make a copy inside the function.
<code>def safe_modify(lst):
local_lst = lst.copy()
local_lst.append(4)
return local_lst
my_list = [1, 2, 3]
print(f"Original list: {my_list}")
new_list = safe_modify(my_list)
print(f"Original list after function: {my_list}")
print(f"New list returned by function: {new_list}")
</code>Summary
Everything in Python is an object with identity, type and value.
Mutable objects can be changed in place; all references see the change.
Immutable objects cannot be changed; operations produce new objects.
Python reuses immutable objects via interning and caching to save memory.
Function arguments are passed by reference, so mutability influences whether a function can modify the caller’s data.
Code Mala Tang
Read source code together, write articles together, and enjoy spicy hot pot together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.