Diving Into Deep Copying
00:00 Unlike shallow copying, deep copying recursively copies objects, and this ensures full independence from the source. Deep copies are new objects distinct from the original.
00:11 They contain copies of nested objects, not just references. As a result, they have no shared references with the original object and can be modified with no risk of causing side effects.
00:24 Once again, we go to the REPL to see some examples.
00:28
The main way to create deep copies in Python is using the deepcopy
function from the built-in copy
module. from copy import deepcopy
. Start with the same inventory dictionary from the previous lesson.
00:41
inventory
again is a dictionary with two keys, fruits
and dairy
. fruits
holds a dictionary with the key-value pairs apple: 50
and banana: 30
. dairy
holds a dictionary with the pairs cheese: 15
and milk: 20
.
00:58
This time, create a backup using the deepcopy
function: backup = deepcopy(inventory)
. Use equality to see that right now their contents are equal,
01:11
and use the is
operator to see that the objects are different.
01:16
Equality is True
and identity is False
, which is just what you’re looking for in a copy. Next, jump straight to mutating one of the inner dictionaries.
01:25
Add the key orange
to the fruits
dictionary and set its value to 40
: inventory
['fruits']['orange'] = 40
.
01:35
Examine inventory
at the key fruits
01:39
and you see the keys, apple
, banana
, and orange
. And examine backup
at the key fruits
,
01:47
apple
, banana
, and no orange
. Not only are the objects distinct, but so are the nested objects. For one more piece of evidence, compare the dairy
dictionaries of inventory
and backup
using the is
operator: inventory['dairy']
is backup['dairy']
returns False
.
02:07
They have no connection to each other. At this point, you’re probably thinking, well then, shouldn’t I just use deepcopy
for everything? The thing is, creating copies of all these objects isn’t free.
02:18 There’s extra overhead in terms of computation and memory usage. For this reason, if the descendants of the top-level object you’re copying are themselves immutable, a shallow copy is actually the preferred choice.
02:31
See this example: import copy
from the copy
module once again: import copy as shallow_copy
. Create a list of two strings, milk
and eggs
, and call it cart
.
02:45
cart = ['milk',
'eggs']
. Create a shallow copy of cart
called basket
.
02:53
basket = shallow_copy(cart)
. As a shallow copy, the two lists are distinct objects, but is there a risk of side effects? Well, think about what kind of changes you can make to cart
.
03:06
You could add an item, right? Try cart.
append('bananas')
.
03:14 But what else can you do? Can you mutate any of the existing items? Well, strings are immutable, but they do support augmented assignment allowing you to add to an existing string.
03:27
So try this: cart[0] +=
' chocolate'
with a space at the beginning. Now look at cart
. cart
contains the strings milk chocolate
, eggs
, and bananas
.
03:41
Look back at basket
. Just like it began, basket
only holds the strings milk
and eggs
. See? No side effects.
03:49
The append
operation only affected the top-level object, cart
, which was already distinct from basket
. And the augmented addition of chocolate
to milk
didn’t actually mutate the underlying object, but instead replaced it with a new object.
04:04
And that is what took the first place position in the list cart
, leaving basket
and the original string as they were. So in a situation like this, deepcopy
would’ve been overkill.
04:15
Alright, up to this point, you’ve done all your copying using the copy
module. In the next lesson, we’ll explore the myriad other options Python offers for producing copies.
Become a Member to join the conversation.