Sometimes while programming, in order to prevent having side effects when we want to change an object, we need to create a copy of that object and mutate the copy so that we can later use the original. Python provides methods that we can use to do this. In this post, I will describe the shallow copy and deep copy methods of python that you can effectively use to copy objects even recursively.
Many programmers think that the assignment operator makes a copy of an object. It is really deceptive. When you write code like this:
object2 = object1
You are not copying but aliasing. That is, object2 is getting a reference to the objects which serve as the value of object1. Aliasing could seem intuitive to use, but the caveat there is that if you change the value of any one of the aliased objects, all the objects referencing that value also change. Let’s take an example.
You could see that I made an aliasing between second_names and names in line 2 so that they both reference the same object. When I appended a name to second_names, it reflected in names because they are both referencing the same object.
Sometimes, we don’t want this behavior. We want the fact that when we have made a copy, we have made a copy that is independent from the original copy. That is where python shallow copy and deep copy operations come in. To make this work, we need to import the methods from the copy module: import copy.
How Python shallow copy works with examples
The syntax for python shallow copy is copy.copy(x)
. The x in the argument is the original iterable you want to copy. I need to state here that the iterable that needs to be copied must be mutable. Immutable iterables are not copied.
Let’s take an example of how python shallow copy works on a list.
You can see that the copy, second_names, remained unchanged even after we added items to the original.
Let’s take an example on how python shallow copy works on a dictionary.
You can see in the dictionary also that the python shallow copy function operates on a dictionary as we expected.
You can also do copy on sets; they are mutable iterables. If you want a refresher on iterables, you can check this post.
There is one weakness of python shallow copy. As the name implies, it does not copy deep down. It copies only items at the surface. If in a list or dictionary we have nested items, it will reference them like in the aliasing operation rather than copy them.
Let’s use an example to show this.
Now, you can see that we changed Rose’s grade in the original from ‘C’ to an ‘A’ but the change was reflected in the copy. Too bad! That is behavior we don’t want. This is because python shallow copy does not go deep down or does not copy recursively. We need another type of copy to make both lists or dictionaries independent. That is where python deep copy comes in.
How python deep copy works
Python deep copy will create a new object from the original object and recursively will add all the objects found in the original object to the new object without passing them by reference. That’s cool. That makes our new nested objects copy effectively.
The syntax for deep copy is copy.deepcopy(x[, memo])
. The x in the argument is the original object that has to be copied while memo is a dictionary that keeps a tab on what has already been copied. The memo is very useful in order to avoid recursive copying loops or for deep copy not to copy too much. I find myself using the memo often when I am implementing deep copy in my custom classes.
Now, let’s take an example of python deep copy on a list, a nested list precisely, and see how it performs.
You can see now that the original nested list was changed without affecting the copy.
That goes to show you the power of python as a programming language.
We can take this concept further by showing how to implement shallow copy and deep copy in python using custom classes. All you really need to do is implement two special methods in your classes for whichever you need. If you need to use python shallow copy in your class, implement the __copy__() special method and if you need to use python deep copy, just implement the __deepcopy__() special method.
Let’s show this by examples.
In the code above we defined a Student class with each student having a name, grade and dept. Then we defined a Faculty class that aggregates a list of students. Then in the Faculty class we implemented the __deepcopy__() special method in order to be able to recursively copy the list of students. Finally in the driver codes, lines 25 to 37, we created the objects for the classes and then copied the faculty object to a new faculty object to see how it will run, printing out the students in the new faculty object.
That’s cool. Just love this code. I hope you enjoyed yourself. I would love to receive feedback as comments.
Happy pythoning.
No comments:
Post a Comment
Your comments here!