Mutable/immutable object definitions
immutable object
The value in the memory pointed to by this object cannot be changed. When changing a variable, because the value it refers to cannot be changed, it is equivalent to copying the original value and then changing it, which will open up a new address, and the variable will point to this new address.
mutable object
The value in the memory pointed to by this object can be changed. After the variable (accurately speaking, the reference) changes, the value it refers to changes directly, and there is no copying behavior, and no new outgoing address is opened .
In Python, numeric types ( int
and float
), strings str, and tuples tuple are all immutable types. The list list, dictionary dict, and collection set are mutable types.
Examples of Immutable Objects
The first point to explain is is
to judge whether the id of the two objects is the same, and the ==
judgment is whether the content is the same.
a = 2 b = 2 c = a + 0 c += 0 print(id(a), id(b), id(2)) # id is the same print(c is b) #True
Look at the string again
astr = 'good' bstr = 'good' cstr = astr + '' print(cstr is bstr) # True print(id(astr), id(bstr), id('good')) # The three ids are the same
Same result as numeric types. If this is the case, after the variable is modified, it is notgood
astr = 'good' print (id (astr)) astr += 'aa' print(id(astr)) # id is not the same as above
Since it is an immutable object, the value of the memory corresponding to the variable is not allowed to be changed. When the variable is to be changed, it actually copies the original value and then changes it, opens up a new address, and astr points to this new address (so the ids of the before and after asstr are different). Any more objects pointing to it will be garbage collected. The same is true for int and float types.
Let's look at tuple again.
add = (1, 2, 3) aee = (1, 2, 3) print(id(add), id(aee), id((1, 2, 3))) # id varies aee = (1, 2, 3) print (id (aee)) aee += () # add empty tuple print(id(aee)) # id changed! print (aee) # (1 , 2,3
Although it seems that (1 ,2, 3)
it should be consistent with the above. Is this a mutable object? look again
add = (1, 2, 3) aee = add print(id(aee), id(add)) # These two ids are the same aee += (4, 5, 6) print(id(aee)) # aee's id has changed! print(add) # add is still (1, 2, 3) unchanged
It is consistent with the numeric type and str type again. In the case of mutable objects add = aee
, they point to the same address (same id) for sure. But not different references to the same object, because if so, a change in aee would cause a change in add, which is not the case in a tuple. So tuple is an immutable object, but it is slightly different from str and numeric types. Usually, the immutability of a tuple means that the value stored in it cannot be changed (in some special cases, such as a list stored in a tuple, the elements in the list can be changed. But in fact, the tuple has not been changed ).
For str、int、float
as long as they are of the same type and the values are the same, then their ids are the same. (Why do you say the types are the same?)
a = 2.0 b = 2 print(a is b) # False, one int and one float, different types
2 and 2.0 are not on the same address.
Mutable Object Example
lis = [1, 2, 3] lis2 = [1, 2, 3] # Although their contents are the same, they point to different memory addresses print(lis is lis2) print(id(lis), id(lis2), id([1, 2, 3])) # all three ids are different
In the case of assignment
alist = [1, 2, 3] # alist is actually a reference to the object, blist = alist is the transfer of the reference, now both references point to the same object (address) blist = alist print(id(alist), id(blist)) # id is the same # So one change will affect the other blist.append(4) print(alist) # Change blist, alist also becomes [1 ,2 ,3 4] print(id(alist), id(blist)) # id is the same as the id when the above value has not changed
blist = alist
this sentence. alist
It's actually a reference to an object, blist = alist
i.e. pass by reference, now both references point to the same object (address). So one change will affect the other.
look at the set again
abb = {1, 2, 3} acc = fig print(id(abb), id(acc)) acc.add(4) print(abb) # {1, 2, 3, 4} print(id(abb), id(acc)) # equal
It is the same as the example in the list above.
Since the object to which the variable refers can be modified, it does not need to be copied and then changed, but is directly changed in place, so no new memory will be opened, and the id will remain unchanged before and after the change.
Of course, this is not the case with immutable objects, you can compare it with this
abc = 3 dd = abc dd = 43 print(abc) # 3, does not change with the change of dd
But if it is a copy, it is just copying the content, and it is not passed a reference. This is especially useful when you want to use the values of the list without modifying the original list.
blist = alist[:] # or alist.copy() print(alist is blist) # False blist.append(4) print(alist) # still [1, 2, 3] no change
as function parameter
test_list = [1, 2, 3, 4] test_str = 'HAHA' def change(alist): alist.append(5) def not_change(astr): astr.lower() change(test_list) not_change(test_str) print(test_list) # changed the original value print(test_str) # no change
Of course, if you don't want to change the value of the original list, the parameter can be passed in a copy of the column variable.alsit[:]
interesting example
Looking at an 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, the id has changed. # So now a2, a1 are not two references to the same object, a2 changes a1 will not change a2 = a2 + [4] # In this equation, the a2 on the right is still the same as the id of a1. Once the assignment is successful, a2 points to the new object print(id(1), id(a2)) # Not equal, the id of a2 has changed print(a1) # [1, 2, 3] does not change
If so write
a1 = [1, 2, 3] a2 = a1 print(id(a1), id(a2)) a2 += [4] # Equivalent to calling a2.extend([4]), no new objects are generated for in-situ changes print(id(1), id(a2)) # equal, the id of a2 has not changed print(a1)
The difference is that a2 += [4]
this sentence is equivalent to calling a2.extend([4])
and changing in place, and no new objects are generated.