DEV Community

Super Kai (Kazuya Ito)
Super Kai (Kazuya Ito)

Posted on

Shallow Copy & Deep Copy in Python (3)

Buy Me a Coffee

*Memo:

  • My post explains the shallow and deep copy of a list.
  • My post explains the shallow and deep copy of a tuple.
  • My post explains the shallow and deep copy of the set with a tuple.
  • My post explains the shallow and deep copy of the set with an iterator.
  • My post explains the shallow and deep copy of a dictionary.
  • My post explains the shallow and deep copy of an iterator.
  • My post explains a set and the set with copy.

The same set is always referred to if copied.


The set with a frozenset is experimented, doing normal, shallow and deep copy as shown below:

*Memo:

  • A set can have the hashable types of elements like str, bytes, int, float, complex, bool, tuple, frozenset, range and iterator but cannot have the unhashable types of elements like bytearray, list, set and dict.
  • The same frozenset is always referred to unless deep-copied.

<Normal Copy>:

*Memo:

  • A and B refer to the same shallow set and deep frozenset.
  • is keyword can check if A and B refer to the same set or frozenset.
    ### Shallow set ##
#   ↓                ↓ 
A = {frozenset(['a'])}
   # ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ Deep frozenset
B = A

print(A) # {frozenset({'a'})}
print(B) # {frozenset({'a'})}

print(A is B)
# True

print(A.pop()) # frozenset({'a'})
print(B.pop()) # KeyError: 'pop from an empty set'
Enter fullscreen mode Exit fullscreen mode

<Shallow Copy>:

set.copy() does shallow copy as shown below:

*Memo:

  • A and B refer to different shallow sets.
  • A and B refer to the same deep frozenset.
  • The same frozenset is always referred to unless deep-copied.
A = {frozenset(['a'])}
B = A.copy()

print(A) # {frozenset({'a'})}
print(B) # {frozenset({'a'})}

print(A is B)
# False

A = A.pop()
B = B.pop()

print(A) # frozenset({'a'})
print(B) # frozenset({'a'})

print(A is B)
# True
Enter fullscreen mode Exit fullscreen mode

The below with set.copy() and frozenset.copy() which does shallow copy is equivalent to the above:

A = {frozenset(['a'])}
B = A.copy()
B.clear()
B.add(A.copy().pop().copy())

print(A) # {frozenset({'a'})}
print(B) # {frozenset({'a'})}

print(A is B)
# False

A = A.pop()
B = B.pop()

print(A) # frozenset({'a'})
print(B) # frozenset({'a'})

print(A is B)
# True
Enter fullscreen mode Exit fullscreen mode

The below with copy.copy() which does shallow copy is equivalent to the above:

import copy

A = {frozenset(['a'])}
B = copy.copy(A)

print(A) # {frozenset({'a'})}
print(B) # {frozenset({'a'})}

print(A is B)
# False

A = A.pop()
B = B.pop()

print(A) # frozenset({'a'})
print(B) # frozenset({'a'})

print(A is B)
# True
Enter fullscreen mode Exit fullscreen mode

The below with copy.copy() which does shallow copy is equivalent to the above:

import copy

A = {frozenset(['a'])}
B = copy.copy(A)
B.clear()
B.add(copy.copy(copy.copy(A).pop()))

print(A) # {frozenset({'a'})}
print(B) # {frozenset({'a'})}

print(A is B)
# False

A = A.pop()
B = B.pop()

print(A) # frozenset({'a'})
print(B) # frozenset({'a'})

print(A is B)
# True
Enter fullscreen mode Exit fullscreen mode

The below with set() which does shallow copy is equivalent to the above:

A = {frozenset(['a'])}
B = set(A)

print(A) # {frozenset({'a'})}
print(B) # {frozenset({'a'})}

print(A is B)
# False

A = A.pop()
B = B.pop()

print(A) # frozenset({'a'})
print(B) # frozenset({'a'})

print(A is B)
# True
Enter fullscreen mode Exit fullscreen mode

The below with set() which does shallow copy and frozenset() which doesn't do shallow copy is equivalent to the above:

A = {frozenset(['a'])}
B = set(A)
B.clear()
B.add(frozenset(set(A).pop()))

print(A) # {frozenset({'a'})}
print(B) # {frozenset({'a'})}

print(A is B)
# False

A = A.pop()
B = B.pop()

print(A) # frozenset({'a'})
print(B) # frozenset({'a'})

print(A is B)
# True
Enter fullscreen mode Exit fullscreen mode

<Deep Copy>:

copy.deepcopy() does deep copy as shown below:

*Memo:

  • A and B refer to the different shallow and deep frozensets.
  • copy.deepcopy() should be used because it's safe, doing copy deeply while set.copy(), copy.copy() and set() aren't safe, doing copy shallowly.
import copy

A = {frozenset(['a'])}
B = copy.deepcopy(A)

print(A) # {frozenset({'a'})}
print(B) # {frozenset({'a'})}

print(A is B)
# False

A = A.pop()
B = B.pop()

print(A) # frozenset({'a'})
print(B) # frozenset({'a'})

print(A is B)
# False
Enter fullscreen mode Exit fullscreen mode

Additionally, the below is the 3D set with a 2D frozenset:

import copy

A = {frozenset([frozenset(['a'])])}
B = copy.deepcopy(A)

print(A) # {frozenset({frozenset({'a'})})}
print(B) # {frozenset({frozenset({'a'})})}

print(A is B)
# False

A = A.pop()
B = B.pop()

print(A) # frozenset({frozenset({'a'})})
print(B) # frozenset({frozenset({'a'})})

A = set(A).pop()
B = set(B).pop()

print(A) # frozenset({'a'})
print(B) # frozenset({'a'})

print(A is B)
# False
Enter fullscreen mode Exit fullscreen mode

Top comments (0)