copy – or not?

Somewhere close to being on par with finding out about Santa, the Easter Bunny and the Tooth Fairy is the discovery at an assignment (listb=lista) in Python is only the creation of another name or label that points to the same data.

Really? What’s the point?

The copy module is essential to create “real” copies of changeable (‘mutable”) objects that can be altered seperately.

copy.copy(x) creates a “shallow copy”

copy.deepcopy(x) creates a “deep copy”

There is no difference between them unless you are dealing with objects that contain other objects, like a tuple that contains some lists. In that case, you may want to use the deep copy if it is important for the copied values to have their own existance. The logically inconsistent behavior here is that a copy created by shallow copy maintains its own values unless it has copied compound objects and then it acts like it contains pointers.

Two reasonably complete ‘studies’ of copies follow, for your enjoyment, that demonstrate the points.

First lets look at 4 lists of data; an original, an assigned copy, a ‘shallow’ copy made with copy.copy and a ‘deep’ copy make with copy.deepcopy:

importcopy
othercolor="blue"
print('the last color in a list will be the variable othercolor - bluetostart')
alist=['red','orange','yellow','violet',othercolor]
blist=alist
clist=copy.copy(alist)
dlist=copy.deepcopy(alist)
print('othercolor=',othercolor)
print('alist:',alist)
print('blistassignment:',blist)
print('clistshallow:',clist)
print('dlistdeep:',dlist)
print('changing other color to "green"')
othercolor='green'
print('so now ............')
print('othercolor=',othercolor)
print('alist:',alist)
print('blist assignment:',blist)
print('clist shallow:',clist)
print('dlist deep:',dlist)
print('changing alist[0] to indigo')
alist[0]='indigo'
print('so now............')
print('othercolor=',othercolor)
print('alist:',alist)
print('blist assignment:',blist)#blistwillchangewithalist
print('clist shallow:',clist)#canddlistmaintaingtheirseparatevalues
print('dlist deep:',dlist)
print('c and d have their own values now')
clist[3]="mauve"
print('clistshallow:',clist)#canddlistmaintaingtheirseparatevalues
print('dlistdeep:',dlist)
print('changing blist[0] to green to see if alist follows')
blist[0]=othercolor
print('alist:',alist)
print('blistassignment:',blist)#alistfollowsblistandvisaversa

Yeilds……..
the last color in alist will be the variable othercolor – blue to start
othercolor = blue
alist: [‘red’, ‘orange’, ‘yellow’, ‘violet’, ‘blue’]
blist assignment: [‘red’, ‘orange’, ‘yellow’, ‘violet’, ‘blue’]
clist shallow: [‘red’, ‘orange’, ‘yellow’, ‘violet’, ‘blue’]
dlist deep: [‘red’, ‘orange’, ‘yellow’, ‘violet’, ‘blue’]
changing othercolor to “green”
so now…………
othercolor = green
alist: [‘red’, ‘orange’, ‘yellow’, ‘violet’, ‘blue’]
blist assignment: [‘red’, ‘orange’, ‘yellow’, ‘violet’, ‘blue’]
clist shallow: [‘red’, ‘orange’, ‘yellow’, ‘violet’, ‘blue’]
dlist deep: [‘red’, ‘orange’, ‘yellow’, ‘violet’, ‘blue’]
changing alist[0] to indigo
so now…………
othercolor = green
alist: [‘indigo’, ‘orange’, ‘yellow’, ‘violet’, ‘blue’]
blist assignment: [‘indigo’, ‘orange’, ‘yellow’, ‘violet’, ‘blue’]
clist shallow: [‘red’, ‘orange’, ‘yellow’, ‘violet’, ‘blue’]
dlist deep: [‘red’, ‘orange’, ‘yellow’, ‘violet’, ‘blue’]
c and d have their own values now
clist shallow: [‘red’, ‘orange’, ‘yellow’, ‘mauve’, ‘blue’]
dlist deep: [‘red’, ‘orange’, ‘yellow’, ‘violet’, ‘blue’]
changing blist to see if alist follows
alist: [‘green’, ‘orange’, ‘yellow’, ‘violet’, ‘blue’]
blist assignment: [‘green’, ‘orange’, ‘yellow’, ‘violet’, ‘blue’]

….and now lets copy and manipulte some compound objects for your enlightenment:

importcopy
alist=[1,2,3]
blist=[4,5,6]
clist=[7,8,9]
thetuple=(alist,blist,clist)
shallowtup=copy.copy(thetuple)
deeptup=copy.deepcopy(thetuple)
print('So, our lists and tuples are:')
print(alist,blist,clist)
print(thetuple)
print(shallowtup)
print(deeptup)
print()
alist[0]=0
print('alist[0] changed to "0"')
print(alist)
print('Our original tuple is now changed')
print(thetuple)
print('Our shallow copy changes with the original')
print(shallowtup)
print('But the deep copy maintains its own data')
print(deeptup)

Yeilds……..
So, our lists and tuples are:
[1, 2, 3] [4, 5, 6] [7, 8, 9]
([1, 2, 3], [4, 5, 6], [7, 8, 9])
([1, 2, 3], [4, 5, 6], [7, 8, 9])
([1, 2, 3], [4, 5, 6], [7, 8, 9])

alist[0] changed to “0”
[0, 2, 3]
Our original tuple is now changed
([0, 2, 3], [4, 5, 6], [7, 8, 9])
Our shallow copy changes with the original
([0, 2, 3], [4, 5, 6], [7, 8, 9])
But the deep copy maintains its own data
([1, 2, 3], [4, 5, 6], [7, 8, 9])