Copying mutable objects in Python

- - Python, Tutorials

An assignment statement in python does not create copies of objects. It binds the name to the object. While working with mutable objects and/or collections of mutable objects, it creates inconsistencies and hence it would be of interest to us to have ways to make real copies of the objects. Essentially, we would require copies such that modifying it would not modify the original object. An example for what happens when we use assignment statements to make copies of mutable objects.

 

>>> fruits = ["apple", "mango", "orange"]
>>> fruits_copy = fruits
>>> id(fruits)
140684382177688
>>> id(fruits_copy)
140684382177688
>>> fruits_copy.append("grapes")
>>> fruits_copy
['apple', 'mango', 'orange', 'grapes']
>>> fruits
['apple', 'mango', 'orange', 'grapes']
>>>

 

The above example demonstrates how using an assignment statement for copying a mutable object has an impact on the original object when the later one is modified.

 

Python’s built-in mutable collections like lists, dicts, and sets can be copied by calling their factory functions on an existing collection.

 

new_list = list(original_list)
new_dict = dict(original_dict)
new_set = set(original_set)

However, this only makes a shallow copy of the objects and goes only a level deep in the recursion tree.

 

A shallow copy refers to construction of a new object followed by populating it with the references to the child objects found in the original object. This implies that a shallow copy is only one level deep. The recursion tree on copying does not proceed further on childs of the object.

 

>>> x = [[1, 2 , 3], [4, 5, 6]]
>>> x_copy = list(x)
>>> id(x) == id(x_copy)
False
>>> x_copy.append([7, 8, 9])
>>> x_copy
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> x
[[1, 2, 3], [4, 5, 6]]

 

In the above example, since x_copy is a new object and the contents upto one level deep are copied to the object, it does not affect the original object. But, remember a shallow copy is only one level deep while all other childs are only referenced and not copied as new ones. Following example should explain it.

 

>>> x = [[1, 2, 3], [4, 5, 6]]
>>> x_copy = list(x)
>>> x_copy[0][0] = "Changed"
>>> x_copy
[['Changed', 2, 3], [4, 5, 6]]
>>> x
[['Changed', 2, 3], [4, 5, 6]]

 

On the flip side, a deep copy is a recursive process. It initially constructs a new object followed by recursively populating it with copies of the child objects found in the original object. Deep copy walks the complete object tree to create a fully independent clone of the original object and all of its childs.

 

>>> import copy
>>> x = [[1, 2, 3], [4, 5, 6]]
>>> x_copy = copy.deepcopy(x)
>>> id(x) == x_copy
False
>>> x_copy
[[1, 2, 3], [4, 5, 6]]
>>> x
[[1, 2, 3], [4, 5, 6]]
>>> x_copy[0][0] = "New Object confirmation"
>>> x_copy
[['New Object confirmation', 2, 3], [4, 5, 6]]
>>> x
[[1, 2, 3], [4, 5, 6]]
>>>

The above example shows a deep copy and hence change in the copied object does not have any effect on the original object.

Bhishan Bhandari [22] A one man army producing contents and maintaining this blog. I am a hobbyist programmer and enjoy writing scripts for automation. If you'd like a process to be automated through programming, I also sell my services at Fiverr . Lately, I like to refresh my Quora feeds. Shoot me messages at bbhishan@gmail.com  

There Are 1 Comment On This Article.

Leave a Reply

Your email address will not be published. Required fields are marked *