SoFunction
Updated on 2025-03-01

A brief discussion on mutable and immutable objects in Python

What is a mutable/immutable object

An immutable object, the value in memory pointed to by the object cannot be changed. When changing a variable, since the value it refers to cannot be changed, it is equivalent to copying the original value and then changing it. This will open up a new address and the variable points to the new address.

A variable object whose value in memory pointed to can be changed. After the variable (to be precise, a reference) is changed, the value it refers to is actually changed directly, and there is no copying behavior, nor is it opened up a new address. In layman's terms, it is changed in place.

In Python, numeric types (int and float), string str, and tuple tuple are all immutable types. List list, dictionary dict, and set set are mutable types.

It's more intuitive to read the code. Look at immutable objects first

Example of immutable objects

Let me first explain that is to determine whether the ids of the two objects are the same, while == determines whether the contents are the same.

a = 2
b = 2
c = a + 0 
c += 0

print(id(a), id(b), id(2)) #The ids are the sameprint(c is b) #True

Let's look at the strings

astr = 'good'
bstr = 'good'
cstr = astr + ''
print(cstr is bstr) # True
print(id(astr), id(bstr), id('good')) # Threeidsame

The same result as the numeric type. If the following situation is the following, the variable will not be good after modification

astr = 'good'
print(id(astr))
astr += 'aa'
print(id(astr)) # idDifferent from the above

Since it is an immutable object, the value of the corresponding memory of the variable is not allowed to be changed. When the variable is to be changed, it is actually copying the original value and then changing it, opening a new address, and astr points to the new address (so the ids of the front and rear astr are different). The value corresponding to the original astr will be garbage collected because no longer has an object pointing to it. This is the same for int and float types.

Look at tuple again

add = (1, 2, 3)
aee = (1, 2, 3)
print(id(add), id(aee), id((1, 2, 3))) # ids vary
aee = (1, 2, 3)
print(id(aee))
aee += () # Add empty tupleprint(id(aee)) # id has changed!print(aee) #(1 ,2,3)

Although it seems that they are (1,2,3), it should be consistent with the above. Is this a mutable object? See again

add = (1, 2, 3)
aee = add 
print(id(aee), id(add)) #These two ids are the sameaee += (4, 5, 6)
print(id(aee)) # aee's id has changed!print(add) # addstill(1, 2, 3)No change

It is consistent with the numeric type and str type. If it is a mutable object add = aee, it is certain that they point to the same address (the same id). But it is not a different reference to the same object, because if so, the change of aee will cause the change of add, which is not the case in tuple. So tuple is an immutable object, but it is slightly different from str and numeric types. The usual tuple is immutable more often means that the value stored in it cannot be changed (in some special cases, such as the list stored in the tuple can change the elements in the list. But in fact, this tuple has not been changed).

For str, int, and float, as long as the values ​​are the same when they are of the same type, their ids are the same. (Why do you want to say that the types are the same?)

a = 2.0
b = 2
print(a is b) # False, oneintonefloat,Different types

2 and 2.0 are not on the same address.

Examples of variable objects

 lis = [1, 2, 3]
lis2 = [1, 2, 3]
# Although their content is the same, they point to different memory addressesprint(lis is lis2)
print(id(lis), id(lis2), id([1, 2, 3])) # ThreeidAll are different

Looking at the assignment situation

alist = [1, 2, 3]
# alist is actually a reference to the object, blist = alist is the passing of the reference. Now both references point to the same object (address)blist = alist
print(id(alist), id(blist)) # same as id# So one of the changes will affect the other(4)
print(alist) # Change blist, alist also becomes [1 , 2 , 3 4]print(id(alist), id(blist)) # id, the same is true for the id when the above value has not changed

blist = alist. alist is actually a reference to the object, blist = alist is the passing of the reference, and now both references point to the same object (address). So one of the changes will affect the other

Check it out again

abb = {1, 2, 3}
acc = abb
print(id(abb), id(acc))
(4)
print(abb) # {1, 2, 3, 4} 
print(id(abb), id(acc)) # equal

Consistent with the example listed above.

Since the object referred to by the variable object can be modified, there is no need to copy a copy and then change it, and it will be changed directly on the spot, so new memory will not be opened up, and the id will not change before and after the change.

Of course, this is not the case with immutable objects. You can compare them with this

abc = 3
dd = abc
dd = 43
print(abc) # 3,Not withddChanges by changes

However, if it is a copy, it is just copying the content, and the passed without reference. This is especially useful when you want to use the value of the list but don't want to modify the original list.

blist = alist[:] # or ()
print(alist is blist) # False
(4)
print(alist) # still[1,2 ,3]No change

As function parameter

As a function parameter, the same is true. Variable types pass references, while immutable types pass content.

test_list = [1, 2, 3, 4]
test_str = 'HAHA'


def change(alist):
  (5)


def not_change(astr):
  ()


change(test_list)
not_change(test_str)
print(test_list) # Change the original valueprint(test_str) # No change

Of course, if you do not want to change the value of the original list, you can pass the parameter into a copy of the column change. alsit[:]

Interesting examples

Let’s look at another interesting example, we know that list can be used + to add a list.

a1 = [1, 2, 3]
a2 = a1
print(id(a1), id(a2))
# Actually a2 points to the new object, and the id has changed.# So now a2 and a1 are not two references to the same object, a2 changes a1 will not changea2 = a2 + [4] # In this equation, the right a2 is the same as the id of a1. Once the assignment is successful, a2 points to the new object.print(id(1), id(a2)) # A2's id has changedprint(a1) # [1, 2, 3]No change

If so, write

a1 = [1, 2, 3]
a2 = a1
print(id(a1), id(a2))
a2 += [4] # It is equivalent to calling ([4]), and no new object is generated when the change is in placeprint(id(1), id(a2)) # is equal, the id of a2 has not changedprint(a1) 

The difference is that a2 += [4], which is equivalent to calling ([4]) and changing it in place, and no new objects are generated.

The above brief discussion of mutable and immutable objects in Python is all the content I have shared with you. I hope you can give you a reference and I hope you can support me more.