Advanced Python 9 | Mutable vs. Immutable, Assign, Shallow Copy, and Deep Copy
Advanced Python 9 | Mutable vs. Immutable, Assign, Shallow Copy, and Deep Copy

- Mutable and Immutable Objects
(1) The Definition of the Mutable Objects
An immutable object means that if we change the value of this object, then the address of this object will not be changed.
(2) The Definition of the Immutable Objects
An immutable object means that if we change the value of this object, then the address of this object will be changed.
(3) Mutable and Immutable Datatypes in Python
Mutable: list, dictionary, set
Immutable: integer, float, boolean, tuple, string
(4) Testing Mutable and Immutable
Based on the definition of the mutable and immutable, we can create a function for us to show if an object is mutable or not by changing its value and then check it’s address.
def is_mutable(var): | |
""" | |
This function has one argument as its input, this | |
input varible is the variable for checking whether or | |
not it is a mutable datatype or an immutable datatype. | |
The returned value of this function will be a boolean, | |
and True means the datatype of the input variable is | |
mutable while False means the datatype of the input | |
variable is immutable. | |
Supported datatype: | |
- integer | |
- string | |
- boolean | |
- float | |
- tuple | |
- set | |
- list | |
- dictionary | |
""" | |
# get the address of the variable | |
ID = id(var) | |
# change the value of the variable | |
# if the variable is a set | |
try: | |
var.add('testing') | |
typ = 0 | |
except AttributeError: | |
# if the variable is a list | |
try: | |
var.append('testing') | |
typ = 0 | |
except AttributeError: | |
# if the variable is a dictionary | |
try: | |
var['testing'] = 'testing' | |
typ = 0 | |
# if the variable is not a set, a list, | |
# or a dictionary, then print use type() | |
# to find out the data type | |
except TypeError: | |
typ = type(var) | |
# if the variables is an int | |
if typ == int: | |
var += 1 | |
# if the variables is a string | |
elif typ == str: | |
var += 'testing' | |
# if the variables is a boolean | |
elif typ == bool: | |
var = not var | |
# if the variables is a float | |
elif typ == float: | |
var += 1.0 | |
# if the variables is a tuple | |
elif typ == tuple and var != ('testing', 'testing'): | |
var = ('testing', 'testing') | |
elif typ == tuple and var == ('testing', 'testing'): | |
var = (0, 'testing') | |
# we just support the basic data types in python, | |
# any other datatypes will raise an error | |
elif typ != 0: | |
assert 0==1, str(typ)+': Datatype not support.' | |
# compare the new address with the original one | |
# if the address changes, then it's immutable | |
# if the address remains the same, then it's mutable | |
return ID == id(var) |
2. Assign, Shallow Copy, and Deep Copy
(1) Acknowledge
People find it hard to understand the difference between the assignment statement and the copy (including copy, shallow copy, and deep copy) statement. Thanks to the lolviz package from Terence Parr, we can now state this confusing problem in a visualized and clear way.
Install lolviz,
$ brew install graphviz
$ pip install lolviz
Import packages,
from lolviz import *
from copy import *
(2) Assign, Shallow Copy, Deepcopy
Assign in the python means to point two variables to the same mutable object. For immutable objects, they will give the value to a new immutable object.
Shallow Copy in the python is exactly the copy() function (or method) which means to point two variables to two different mutable objects, but if there’s any mutable objects inside that these two different objects, they will not be copied and they are still pointed by these two different objects.
Deepcopy means to copy everything, including objects in the objects.
- For a immutable object, assign, shallow copy, and deepcopy mean exactly the same thing,
X = 1
Y = X
callviz(varnames=['X','Y'])

X = 1
Y = copy(X)
callviz(varnames=['X','Y'])

X = 1
Y = deepcopy(X)
callviz(varnames=['X','Y'])

- For a immutable object, assign means to point the variable to exactly the same object, whereas shallow copy means only copy the overall mutable object, but not the other mutable objects inside this object. Deepcopy means to copy both the overall mutable object and the mutable objects inside the data type. Here are some examples,
X = [1,2]
Y = X
callviz(varnames=['X','Y'])

X = [1,2]
Y = copy(X)
callviz(varnames=['X','Y'])

X = [1,2]
Y = X.copy()
callviz(varnames=['X','Y'])

X = [1,2]
Y = deepcopy(X)
callviz(varnames=['X','Y'])

X = [[1,2],[3,4]]
Y = X
callviz(varnames=['X','Y'])

X[0] = ['p', 'q']
callviz(varnames=['X','Y'])

X = [[1,2],[3,4]]
Y = X.copy()
callviz(varnames=['X','Y'])

X[0] = ['p', 'q']
callviz(varnames=['X','Y'])

X = [[1,2],[3,4]]
Y = deepcopy(X)
callviz(varnames=['X','Y'])

X[0] = ['p', 'q']
callviz(varnames=['X','Y'])

(3) Practice
View the following two code blocks and find the difference in their data structure.
X = [[1,[1,2]],'a','b']
Y = copy(X)
Y[2] = ['p']
X = copy(Y)
callviz(varnames=['X','Y'])
and
X = [[1,[1,2]],'a','b']
Y = X
Y[2] = ['p']
X = Y
callviz(varnames=['X','Y'])
