What is going on with Python's deep and shallow copies?

life is short i use python

1. Assignment

in Python,
The assignment of the object is to pass the object reference (memory address),
assignment (=),
is to create a new reference to the object,
Modifying any one of these variables will affect the other

will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = will 
print('will>>', will, id(will))
print('wilber>>', wilber, id(wilber))
print('will elements of id>>', [id(ele) for ele in will])
print('wilber elements of id>>',[id(ele) for ele in wilber])
print('---'*30)
will[0] = "Wilber"
will[2].append("CSS")
print('will>>', will, id(will))
print('wilber>>', wilber, id(wilber))
print('will elements of id>>', [id(ele) for ele in will])
print('wilber elements of id>>',[id(ele) for ele in wilber])
#output as
will>> ['Will', 28, ['Python', 'C#', 'JavaScript']] 43988040
wilber>> ['Will', 28, ['Python', 'C#', 'JavaScript']] 43988040
will elements of id>> [31326928, 493056320, 43988808]
wilber elements of id>> [31326928, 493056320, 43988808]
------------------------------------------------------------------------------------------
will>> ['Wilber', 28, ['Python', 'C#', 'JavaScript', 'CSS']] 43988040
wilber>> ['Wilber', 28, ['Python', 'C#', 'JavaScript', 'CSS']] 43988040
will elements of id>> [44016672, 493056320, 43988808]
wilber elements of id>> [44016672, 493056320, 43988808]

Source code information e-book: Click here to jump to the end of the article to get the business card

Two, shallow copy

A shallow copy creates a new object,
In this example "wilber is not will" but,
For elements in an object,
Shallow copy will only use the reference (memory address) of the original element,
That is to say "wilber[i] is will[i]"

When modifying will:
Since the first element of the list is an immutable type,
So the first element of the list corresponding to will will use a new object 39758496;

But the third element of the list is a mutable type,
The modification operation will not generate a new object, so the modification result of will will be reflected on wilber accordingly

shallow copy:

Create a new object,
but what it contains is a reference to the item contained in the original object
(If one of the objects is modified by reference, the other will also be modified)
{1, full slice method; 2, factory function, such as list(); 3, copy() function of copy module}

Slices are also shallow copies

import copy
will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = copy.copy(will)
print('will>>   ', will, id(will))
print('wilber>> ', wilber, id(wilber))
print('will elements of id>>  ', [id(ele) for ele in will])
print('wilber elements of id>>',[id(ele) for ele in wilber])
print('---'*30)
will[0] = "Wilber"
will[2].append("CSS")
print('will>>   ', will, id(will))
print('wilber>> ', wilber, id(wilber))
print('will elements of id>>  ', [id(ele) for ele in will])
print('wilber elements of id>>',[id(ele) for ele in wilber])

will>>    ['Will', 28, ['Python', 'C#', 'JavaScript']] 43862024
wilber>>  ['Will', 28, ['Python', 'C#', 'JavaScript']] 43861896
will elements of id>>   [31261392, 493056320, 43862088]
wilber elements of id>> [31261392, 493056320, 43862088]
------------------------------------------------------------------------------------------
will>>    ['Wilber', 28, ['Python', 'C#', 'JavaScript', 'CSS']] 43862024
wilber>>  ['Will', 28, ['Python', 'C#', 'JavaScript', 'CSS']] 43861896
will elements of id>>   [43886384, 493056320, 43862088]
wilber elements of id>> [31261392, 493056320, 43862088]

3. Deep copy

Similar to shallow copy, deep copy also creates a new object,
In this example "wilber is not will" however,
For elements in an object,
Deep copy will regenerate a copy (there are special cases, which will be explained below),
Instead of simply using the reference (memory address) of the original element

Deep copy:

Create a new object,
and recursively copies the objects it contains
(Modify one of them, the other will not change)
{deep.deepcopy() function of the copy module}

import copy
will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = copy.deepcopy(will)
print('will>>   ', will, id(will))
print('wilber>> ', wilber, id(wilber))
print('will elements of id>>  ', [id(ele) for ele in will])
print('wilber elements of id>>',[id(ele) for ele in wilber])
print('---'*30)
will[0] = "Wilber"
will[2].append("CSS")
print('will>>   ', will, id(will))
print('wilber>> ', wilber, id(wilber))
print('will elements of id>>  ', [id(ele) for ele in will])
print('wilber elements of id>>',[id(ele) for ele in wilber])
# output as
will>>    ['Will', 28, ['Python', 'C#', 'JavaScript']] 37373960
wilber>>  ['Will', 28, ['Python', 'C#', 'JavaScript']] 37373832
will elements of id>>   [31195856, 493056320, 37374024]
wilber elements of id>> [31195856, 493056320, 37373768]
------------------------------------------------------------------------------------------
will>>    ['Wilber', 28, ['Python', 'C#', 'JavaScript', 'CSS']] 37373960
wilber>>  ['Will', 28, ['Python', 'C#', 'JavaScript']] 37373832
will elements of id>>   [37398264, 493056320, 37374024]
wilber elements of id>> [31195856, 493056320, 37373768]

4. Special circumstances

For non-container types
(such as numbers, strings, and other 'atomic' types of objects)
no copy
That is to say,
For these types,
"obj is copy.copy(obj)" ,"obj is copy.deepcopy(obj)"
If the tuple variable only contains atomic type objects, it cannot be deep copied, see the following example

import copy
books=('a','b','c')
books1,books2 =  copy.copy(books),copy.deepcopy(a)
>>books is books1 is books2
# true

a = 'python'
b,c = copy.copy(a),copy.deepcopy(a)
In [19]: a is b is c
Out[19]: True
In [20]: id(a),id(b),id(c)
Out[20]: (55466056, 55466056, 55466056)


In [30]: t1=('a','b','c',['d'])

In [31]: t2,t3 =  copy.copy(t1),copy.deepcopy(t1)

In [32]: t1 is t2 is t3
Out[32]: False

In [33]: id(t1), id(t2), id(t3)
Out[33]: (89247560, 89247560, 88537672)

The assignment of objects in Python is all about object references (memory addresses)
transfer
use copy.copy(),
Shallow copies of objects can be made,
It copies the object, but for elements in the object,
Still use the original reference.
If you need to copy a container object,
and all elements inside it (children of the containing element),
You can use copy.deepcopy() to make a deep copy
For non-container types
(such as numbers, strings, and other 'atomic' types of objects)
not copied
If the tuple variable contains only atomic type objects, it cannot be deep copied

1. Example of a shallow copy of a list

import copy
a = [1,2,3,4,['a','b']] #define a list a
b = a #assignment
c = copy.copy(a) #shallow copy
d = copy.deepcopy(a) #deep copy
a.append(5)
a[0] = '10'
print('A0',a,id(a))

# [1, 2, 3, 4, ['a', 'b'], 5] #a adds an element 5
print('B0',b,id(b))
# [1, 2, 3, 4, ['a', 'b'], 5] #b followed by adding an element 5
print('C0',c,id(c))
# [1, 2, 3, 4, ['a', 'b']] #c stays the same
print('D0',d,id(d))
# [1, 2, 3, 4, ['a', 'b']] #d stays the same
a[4].append('c')
a[4][1]='ASDF'
print('A1',a,id(a))
# [1, 2, 3, 4, ['a', 'b', 'c'], 5] #The list in a (that is, a[4]) adds an element c
print('B1',b,id(a))
# [1, 2, 3, 4, ['a', 'b', 'c'], 5] #b followed by adding an element c
print('C1',c,id(c))
# [1, 2, 3, 4, ['a', 'b', 'c']] #c followed by adding an element c
print('D1',d,id(d))
[1, 2, 3, 4, ['a', 'b']] #d stays the same

2. copy of a single list

names = ['alex','jack','1','mack','racheal','shanshan']
n2 = names
n3 = names.copy()
n4 = names[:]

print('first round','names',names,id(names))
print('first round','n2',n2,id(n2))
print('first round','n3',n3,id(n3))
print('first round','n4',n4,id(n4))

names.append('hery')
names[0]="Alex"
print('second round','names',names,id(names))
print('second round','n2',n2,id(n2))
print('second round','n3',n3,id(n3))
print('second round','n4',n4,id(n4))

output:

first round names ['alex', 'jack', '1', 'mack', 'racheal', 'shanshan'] 167690376
 first round n2 ['alex', 'jack', '1', 'mack', 'racheal', 'shanshan'] 167690376
 first round n3 ['alex', 'jack', '1', 'mack', 'racheal', 'shanshan'] 167692616
 first round n4 ['alex', 'jack', '1', 'mack', 'racheal', 'shanshan'] 167713928
 second round names ['Alex', 'jack', '1', 'mack', 'racheal', 'shanshan', 'hery'] 167690376
 second round n2 ['Alex', 'jack', '1', 'mack', 'racheal', 'shanshan', 'hery'] 167690376
 second round n3 ['alex', 'jack', '1', 'mack', 'racheal', 'shanshan'] 167692616
 second round n4 ['alex', 'jack', '1', 'mack', 'racheal', 'shanshan'] 167713928

3. String copy

import copy
name="hahah"   #string
name1=copy.copy(name)
name2=copy.deepcopy(name)
print('first',id(name),id(name1),id(name2))

sum=111   #number
sum1=copy.copy(sum)
sum2=copy.deepcopy(sum)
print('the second time',id(sum),id(sum1),id(sum2))

output:

First time 31179752 31179752 31179752
 Second time 1702001568 1702001568 1702001568

4. copy of the dictionary

import copy
call = {
    'cpu':[80,25],
    'mem':[80,],
    'disk':[80,]
}
new_call_1 = copy.copy(call)
new_call_2 = copy.deepcopy(call)
print('before fixing call1 for:%s' %(call),id(call))
# #modify new template
call['disk'] = 66
call['disk_2'] = 67
call['cpu'].append(20)
call['cpu'][1]=11
new_call_1['cpu'].append(33)
new_call_1['disk'][0] = 77
new_call_1['mem'] = 75
new_call_2['disk'][0] = 79
# #View the values ​​of old and new templates
print('call1 for:%s' %(call),id(call))
print('new_call_1 for:%s' %(new_call_1),id(new_call_1))
print('new_call_2 for:%s' %(new_call_2),id(new_call_2))

output:

before fixing call1 for:{'cpu': [80, 25], 'mem': [80], 'disk': [80]} 4411328
call1 for:{'cpu': [80, 11, 20, 33], 'mem': [80], 'disk': 66, 'disk_2': 67} 4411328
new_call_1 for:{'cpu': [80, 11, 20, 33], 'mem': 75, 'disk': [77]} 4452424
new_call_2 for:{'cpu': [80, 25], 'mem': [80], 'disk': [79]} 31977616

Python print progress bar

import time
for i in range(0,101,2):
     time.sleep(0.1)
     char_num = i//2      
     per_str = '\r%s%% : %s\n' % (i, '>>>' * char_num) if i == 100 else '\r%s%% : %s'%(i,'*'*char_num)
     print(per_str,end='', flush=True)


👇Questions & Answers · Source Code Acquisition · Technical Exchange · Group learning please contact 👇

Tags: Python Javascript programming language

Posted by zyntrax on Mon, 20 Mar 2023 15:31:41 +1030