Understanding Objects, Identity, Mutability, and Memory Management in Python

Introduction Python is a powerful and flexible language, but to use it effectively, we need to understand how it handles objects, references, and memory. This post explores key concepts such as object identity, mutability, and how arguments are passed to functions, providing essential knowledge for writing efficient and bug-free Python code. What is an Object in Python? In Python, everything is an object: integers, strings, lists, functions, and even classes. Each object has three main properties: Identity → It is a unique number that identifies it in memory, which can be retrieved using id(obj). Type → Defines what kind of object it is, obtained with type(obj). Value → The actual data stored within the object. Example: x = 10 # 10 es un objeto entero print(id(x)) # Muestra la identidad del objeto print(type(x)) # Muestra que es un entero Difference Between a Class and an Object (Instance) Class: A blueprint for creating objects. Object (Instance): It is a concrete version created from a class. Example: class Dog: def __init__(self, name): self.name = name fido = Dog("Fido") # 'fido' is an instance of the Dog class Object Identity id() The id() function returns the memory address of an object. Example: x = 42 print(id(x)) # Displays a number (memory address) Does id() Always Stay the Same? For immutable objects (int, float, str, tuple, bool), modifying them generally creates a new object with a new id. However, due to Python's interning, small integers (-5 to 256) and some strings may retain the same id. For mutable objects (list, dict, set), modifying them keeps the id the same # Immutable object a = 10 print(id(a)) #Initial ID a += 1 print(id(a)) # New ID # Mutable object lst = [1, 2, 3] print(id(lst)) lst.append(4) print(id(lst)) # Same ID Checking Identity and Equivalence == checks if values are equal. is checks if two variables refer to the same object in memory. a = [1, 2, 3] b = a c = [1, 2, 3] print(a == b) # True (values are equal) print(a is b) # True (same memory address) print(a == c) # True (values are equal) print(a is c) # False (different objects in memory) Interning (Memory Optimization) Python optimizes memory by reusing immutable objects in certain cases. Integers (-5 to 256) Small integers (typically between -5 and 256) are interned, meaning they are stored once in memory and reused to improve performance. a = 89 b = 89 print(a is b) # True (same memory address) Strings (simple literals) Python can also apply interning to certain immutable strings, especially when they are short, alphanumeric, and created directly in the code (e.g., s = "hello"). However, dynamically constructed strings (s = "he" + "llo") or those containing special characters may not be automatically interned. s1 = "hello" s2 = "hello" print(s1 is s2) # True (interning applied) Mutability Mutability refers to whether an object's state can be changed after it is created. Mutable vs Immutable Objects A mutable object can change its contents after it is created. An immutable object cannot. For immutable types, modifying a value usually creates a new object. However, due to interning, Python may reuse small integers and simple strings. Immutable Types int, float, str, tuple, bool, frozenset, complex Mutable Types list, dict, set, bytearray Mutable example: lst = [1, 2, 3] lst.append(4) print(lst) # [1, 2, 3, 4] Immutable example: tup = (1, 2, 3) tup[0] = 100 # ❌ Error! Tuples are immutable Reassignment vs Mutation When you reassign a variable, you are not modifying the object itself but rather making the variable point to a new object in memory. This is especially relevant for immutable objects, where any modification results in reassignment rather than mutation. Mutation l1 = [1, 2, 3] l2 = l1 # Both variables point to the same list in memory l1.append(4) # The same object is modified print(l2) # [1, 2, 3, 4] ✅

Mar 13, 2025 - 00:28
 0
Understanding Objects, Identity, Mutability, and Memory Management in Python

Introduction

Python is a powerful and flexible language, but to use it effectively, we need to understand how it handles objects, references, and memory. This post explores key concepts such as object identity, mutability, and how arguments are passed to functions, providing essential knowledge for writing efficient and bug-free Python code.

What is an Object in Python?

In Python, everything is an object: integers, strings, lists, functions, and even classes. Each object has three main properties:

  1. Identity → It is a unique number that identifies it in memory, which can be retrieved using id(obj).

  2. Type → Defines what kind of object it is, obtained with type(obj).

  3. Value → The actual data stored within the object.

Example:

x = 10  # 10 es un objeto entero
print(id(x))   # Muestra la identidad del objeto
print(type(x)) # Muestra que es un entero

Difference Between a Class and an Object (Instance)

An explanatory illustration about classes and instances using Buzz Lightyear as an example. On the left, a technical blueprint of Buzz represents the 'CLASS: Buzz,' showing his general design and characteristics. On the right, three images of Buzz Lightyear labeled 'INSTANCE 1,' 'INSTANCE 2,' and 'INSTANCE 3' symbolize different instances created from the class.

Class: A blueprint for creating objects.

Object (Instance): It is a concrete version created from a class.

Example:

class Dog:
    def __init__(self, name):
        self.name = name

fido = Dog("Fido")  # 'fido' is an instance of the Dog class

Object Identity id()

The id() function returns the memory address of an object.

Example:

x = 42
print(id(x))  # Displays a number (memory address)

Does id() Always Stay the Same?

  • For immutable objects (int, float, str, tuple, bool), modifying them generally creates a new object with a new id. However, due to Python's interning, small integers (-5 to 256) and some strings may retain the same id.

  • For mutable objects (list, dict, set), modifying them keeps the id the same

# Immutable object
a = 10
print(id(a)) #Initial ID
a += 1
print(id(a))  # New ID

# Mutable object
lst = [1, 2, 3]
print(id(lst))
lst.append(4)
print(id(lst))  # Same ID

Checking Identity and Equivalence

  • == checks if values are equal.

  • is checks if two variables refer to the same object in memory.

a = [1, 2, 3]
b = a
c = [1, 2, 3]

print(a == b)  # True (values are equal)
print(a is b)  # True (same memory address)
print(a == c)  # True (values are equal)
print(a is c)  # False (different objects in memory)

Interning (Memory Optimization)

Python optimizes memory by reusing immutable objects in certain cases.

Integers (-5 to 256)

Small integers (typically between -5 and 256) are interned, meaning they are stored once in memory and reused to improve performance.

a = 89
b = 89
print(a is b)  # True (same memory address)

Strings (simple literals)

Python can also apply interning to certain immutable strings, especially when they are short, alphanumeric, and created directly in the code (e.g., s = "hello"). However, dynamically constructed strings (s = "he" + "llo") or those containing special characters may not be automatically interned.

s1 = "hello"
s2 = "hello"
print(s1 is s2)  # True (interning applied)

Mutability

Mutability refers to whether an object's state can be changed after it is created.

Mutable vs Immutable Objects

A mutable object can change its contents after it is created. An immutable object cannot.

For immutable types, modifying a value usually creates a new object. However, due to interning, Python may reuse small integers and simple strings.

Immutable Types

  • int, float, str, tuple, bool, frozenset, complex

Mutable Types

  • list, dict, set, bytearray

Mutable example:

lst = [1, 2, 3]
lst.append(4)
print(lst)  # [1, 2, 3, 4]

Immutable example:

tup = (1, 2, 3)
tup[0] = 100  # ❌ Error! Tuples are immutable

Reassignment vs Mutation

When you reassign a variable, you are not modifying the object itself but rather making the variable point to a new object in memory. This is especially relevant for immutable objects, where any modification results in reassignment rather than mutation.

Mutation

l1 = [1, 2, 3]
l2 = l1  # Both variables point to the same list in memory
l1.append(4)  # The same object is modified
print(l2)  # [1, 2, 3, 4] ✅