References and Copies
When a program makes an assignment such as a = b, a new reference to b is created. For immutable objects such as numbers and strings, this assignment effectively creates a copy of b. However, the behavior is quite different for mutable objects such as lists and dictionaries. Here’s an example:
>>> a = [1,2,3,4] >>> b = a # b is a reference to a >>> b is a True >>> b[2] = -100 # Change an element in b >>> a # Notice how a also changed [1, 2, -100, 4] >>>
Because a and b refer to the same object in this example, a change made to one of the variables is reflected in the other. To avoid this, you have to create a copy of an object rather than a new reference.
Two types of copy operations are applied to container objects such as lists and dictionaries: a shallow copy and a deep copy. A shallow copy creates a new object but populates it with references to the items contained in the original object. Here’s an example:
>>> a = [ 1, 2, [3,4] ] >>> b = list(a) # Create a shallow copy of a. >>> b is a False >>> b.append(100) # Append element to b. >>> b [1, 2, [3, 4], 100] >>> a # Notice that a is unchanged [1, 2, [3, 4]] >>> b[2][0] = -100 # Modify an element inside b >>> b [1, 2, [-100, 4], 100] >>> a # Notice the change inside a [1, 2, [-100, 4]] >>>
In this case, a and b are separate list objects, but the elements they contain are shared. Therefore, a modification to one of the elements of a also modifies an element of b, as shown.
A deep copy creates a new object and recursively copies all the objects it contains. There is no built-in operation to create deep copies of objects. However, the copy.deepcopy() function in the standard library can be used, as shown in the following example:
>>> import copy >>> a = [1, 2, [3, 4]] >>> b = copy.deepcopy(a) >>> b[2][0] = -100 >>> b [1, 2, [-100, 4]] >>> a # Notice that a is unchanged [1, 2, [3, 4]] >>>