Understanding Mutable and Immutable Objects in Python.

Introduction:

Understanding Python's concepts of mutable and immutable objects is crucial for writing efficient and bug-free code. The blog post will explore the differences between mutable and immutable objects, how Python treats them differently, and the implications for writing Python programs.


(Infinity, 2023)

ID and Type

In Python, every object is identified by a unique ID, representing its memory location. Immutable objects like integers and strings maintain a constant ID, while mutable objects such as lists and dictionaries can change their ID when modified. These IDs and types provide crucial insights into how Python manages memory and data.

(Ramjee, 2021)

Mutable Objects:

Mutable objects in Python can be modified after creation. For example, lists and dictionaries are mutable, allowing elements to be added, removed, or altered without changing their identity. Here's an example illustrating the mutability of lists:

list1 = [1, 2, 3]

print(id(list1)) # Output: 140440275444608

list1.append(4)

print(id(list1)) # Output: 140440275444608 (Same ID after modification)


Immutable Objects:

Immutable objects, on the other hand, cannot be changed once they are created. For instance, integers and tuples are immutable in Python. When you perform operations that appear to modify immutable objects, Python creates a new object with the modified value. Here's an example demonstrating the immutability of integers:

x = 10

print(id(x)) # Output: 140440500155040

x += 1

print(id(x)) # Output: 140440500155072 (Different ID after modification)


Tuples and frozen sets in Python are immutable but can contain mutable objects like lists or dictionaries. The mutable objects can be modified while the tuple or frozen set remains immutable. When handling mutable objects within these immutable data structures, care must be taken to avoid unintended modifications and ensure data integrity.


Why Does It Matter:

Understanding the distinction between mutable and immutable objects is crucial for writing efficient and bug-free code. Immutable objects provide safety and prevent unintended modifications, while mutable objects offer flexibility and allow in-place changes. Python treats mutable and immutable objects differently, especially when passing them as arguments to functions.

Argument Passing In Functions:

In Python, parameters are passed to functions by object reference. When you pass a mutable object to a function, any alterations made to the object within the function will impact the original object. However, immutable objects passed to a function remain unchanged outside the function. Here's an example illustrating argument passing:

def modify_list(lst):

lst.append(4)

my_list = [1, 2, 3]

modify_list(my_list)

print(my_list) # Output: [1, 2, 3, 4] (Original list modified)

Difference between assignment and referencing:

Assignment:

  • Assignment involves creating a new object and binding it to a variable.
  • When you assign a value to a variable, you create a new object in memory and associate it with the variable name.
  • Any subsequent changes to the variable will affect only that variable and not other variables referencing the same object.

Referencing:

  • Referencing involves creating a new reference to an existing object in memory.
  • When you assign one variable to another, you create a new reference to the same object in memory.
  • Both variables now refer to the same object, and changes made to one variable will also affect the other variable.

How immutable objects are stored in memory.

In Python, immutable objects, such as integers and strings, are stored in memory as fixed-size blocks. When you create an immutable object, such as an integer with the value 10, Python allocates memory for that object and stores the value 10. Since immutable objects cannot be modified after creation, Python does not need to allocate additional memory. Instead, it can reuse the existing memory block whenever the exact value is required elsewhere in the program.

This approach helps optimize memory usage and improve performance. When you perform operations on immutable objects, Python creates new objects with the updated values, leaving the original objects unchanged. This behavior ensures that the integrity of immutable objects is preserved throughout the program execution.

Memory schema examples:

Example with Immutable Object (Integer):

x = 10

y = x

print(id(x)) # Output: 140440500155040

print(id(y)) # Output: 140440500155040 (Same ID as x)

x += 1

print(id(x)) # Output: 140440500155072 (Different ID after modification)

print(id(y)) # Output: 140440500155040 (ID of y remains the same)


Example with Mutable Object (List):

list1 = [1, 2, 3]

list2 = list1

print(id(list1)) # Output: <memory address 1>

print(id(list2)) # Output: <memory address 1> (Same ID as list1)

list1.append(4)

print(id(list1)) # Output: <memory address 2> (Different ID after modification)

print(id(list2)) # Output: <memory address 1> (ID of list2 remains the same)


In CPython, the NSMALLPOSINTS and NSMALLNEGINTS constants are used to pre-allocate a fixed number of small positive and negative integers, respectively, when the interpreter starts up. These integers typically range from -5 to 256, and their pre-allocation optimizes memory usage and performance for joint operations involving small integers. When you create an integer within this range in Python code, the interpreter returns a reference to the pre-allocated object rather than creating a new object every time. This optimization helps reduce the overhead associated with memory allocation and deallocation, leading to faster execution of Python programs. However, these constants are specific to the CPython implementation and may not be present in other Python implementations.


Integer pre-allocation

In CPython, the standard implementation of Python, the first 262 integers (from -5 to 256) are pre-allocated when the interpreter starts up. These integers are commonly used and frequently appear in Python code. By pre-allocating these integers, CPython aims to optimize memory usage and improve performance for joint operations involving small integers. When an integer within this range is created in Python code, the interpreter returns a reference to the pre-allocated object rather than creating a new object every time. This optimization helps reduce the overhead associated with memory allocation and deallocation, leading to faster execution of Python programs. However, I want to point out that this optimization is specific to CPython and may not be present in other Python implementations.

The mechanism of aliases:

In Python, aliases are created when multiple variables are assigned to the same object in memory. This means that changes made to the object through one variable will affect all aliases, as they all reference the exact memory location. This behavior is fundamental to understanding how variables interact with objects, mainly when dealing with mutable data structures like lists and dictionaries. Awareness of aliases helps prevent unexpected side effects and ensures the code behaves as intended.

Conclusion:

In conclusion, understanding the concepts of mutable and immutable objects is fundamental for writing Python programs efficiently. By grasping how Python treats mutable and immutable objects differently, developers can write more robust and predictable code, leading to better software development practices.

要查看或添加评论,请登录

Limpho Semakale的更多文章

  • How SQL Database Engines Work

    How SQL Database Engines Work

    Introduction: Imagine a library filled with countless books, each neatly organized for easy access. Now, think of a…

  • Demystifying Object and Class Attributes in Python

    Demystifying Object and Class Attributes in Python

    With its simplicity and flexibility, Python offers robust mechanisms for managing attributes within classes…

社区洞察

其他会员也浏览了