DEV Community

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

Posted on • Edited on

Set(frozenset) shallow & deep copy in Python

Buy Me a Coffee

*Memo for shallow and deep copy:

*Memo for others:


Different sets are referred to, shallow-copied and deep-copied.


The 2D set with a 1D frozenset is experimented, doing an assignment and shallow and deep copy as shown below:

*Memo:

  • The 2D set with a 1D frozenset can be shallow-copied and deep-copied.
  • 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.
  • Different frozensets are referred to only if deep-copied according to the experiments.
  • There are an assignment and 2 kinds of copies, shallow copy and deep copy:
    • An assignment is to create the one or more references to the original top level object and (optional) original lower levels' objects, keeping the same values as before.
    • A shallow copy is to create the one or more references to the new top level object and (optional) original lower levels' objects, keeping the same values as before.
    • A deep copy is to create the two or more references to the new top level object and the new lower levels' objects which you desire but at least the new 2nd level objects, keeping the same values as before:
      • A deep copy is the multiple recursions of a shallow copy so a deep copy can be done with multiple shallow copies.
    • Basically, immutable(hashable) objects aren't copied to save memory like str, bytes, int, float, complex, bool and tuple.

<Assignment>:

*Memo:

  • A and B refer to the same outer set and inner frozenset.
  • is keyword can check if A and B refer to the same outer set and inner frozenset.

The 2D set with a 1D frozenset is assigned to a variable without copied as shown below:

    ###### Outer set #####
#   ↓                    ↓ 
A = {frozenset([0, 1, 2])}
   # ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ Inner frozenset
B = A

print(A) # {frozenset({0, 1, 2})}
print(B) # {frozenset({0, 1, 2})}

print(A is B)
# True

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

<Shallow copy>:

*Memo:

  • A and B refer to different outer sets and the same inner frozenset.

set.copy() can shallow-copy the 2D set with a 1D frozenset as shown below:

A = {frozenset([0, 1, 2])}
B = A.copy()

print(A) # {frozenset({0, 1, 2})}
print(B) # {frozenset({0, 1, 2})}

print(A is B)
# False

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

print(A) # frozenset({0, 1, 2})
print(B) # frozenset({0, 1, 2})

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

copy.copy() can shallow-copy the 2D set with a 1D frozenset as shown below:

import copy

A = {frozenset([0, 1, 2])}
B = copy.copy(A)

print(A) # {frozenset({0, 1, 2})}
print(B) # {frozenset({0, 1, 2})}

print(A is B)
# False

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

print(A) # frozenset({0, 1, 2})
print(B) # frozenset({0, 1, 2})

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

set() can shallow-copy the 2D set with a 1D frozenset as shown below:

A = {frozenset([0, 1, 2])}
B = set(A)

print(A) # {frozenset({0, 1, 2})}
print(B) # {frozenset({0, 1, 2})}

print(A is B)
# False

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

print(A) # frozenset({0, 1, 2})
print(B) # frozenset({0, 1, 2})

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

<Deep copy>:

*Memo:

  • A and B refer to different outer sets and inner frozensets.

copy.deepcopy() can deep-copy the 2D set with a 1D frozenset as shown below:

*Memo:

  • copy.deepcopy() should be used because it's safe, deeply copying the 2D set with a 1D frozenset while set.copy(), copy.copy() and set() aren't safe, shallowly copying a 2D set with a 1D frozenset.
import copy

A = {frozenset([0, 1, 2])}
B = copy.deepcopy(A)

print(A) # {frozenset({0, 1, 2})}
print(B) # {frozenset({0, 1, 2})}

print(A is B)
# False

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

print(A) # frozenset({0, 1, 2})
print(B) # frozenset({0, 1, 2})

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

set.copy() and frozenset.copy() cannot deep-copy the 2D set with a 1D frozenset, only shallow-copying the outer set as shown below:

A = {frozenset([0, 1, 2])}
B = A.copy()
B.clear()
B.add(A.copy().pop().copy())

print(A) # {frozenset({0, 1, 2})}
print(B) # {frozenset({0, 1, 2})}

print(A is B)
# False

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

print(A) # frozenset({0, 1, 2})
print(B) # frozenset({0, 1, 2})

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

copy.copy() cannot deep-copy the 2D set with a 1D frozenset, only shallow-copying the outer set as shown below:

import copy

A = {frozenset([0, 1, 2])}
B = copy.copy(A)
B.clear()
B.add(copy.copy(copy.copy(A).pop()))

print(A) # {frozenset({0, 1, 2})}
print(B) # {frozenset({0, 1, 2})}

print(A is B)
# False

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

print(A) # frozenset({0, 1, 2})
print(B) # frozenset({0, 1, 2})

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

set() and frozenset() cannot deep-copy the 2D set with a 1D frozenset, only shallow-copying the outer set as shown below:

A = {frozenset([0, 1, 2])}
B = set(A)
B.clear()
B.add(frozenset(set(A).pop()))

print(A) # {frozenset({0, 1, 2})}
print(B) # {frozenset({0, 1, 2})}

print(A is B)
# False

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

print(A) # frozenset({0, 1, 2})
print(B) # frozenset({0, 1, 2})

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

Additionally, copy.deepcopy() can deep-copy the 3D set with a 2D frozenset as shown below:

import copy

A = {frozenset([frozenset([0, 1, 2])])}
B = copy.deepcopy(A)

print(A) # {frozenset({frozenset({0, 1, 2})})}
print(B) # {frozenset({frozenset({0, 1, 2})})}

print(A is B)
# False

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

print(A) # frozenset({frozenset({0, 1, 2})})
print(B) # frozenset({frozenset({0, 1, 2})})

print(A is B)
# False

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

print(A) # frozenset({0, 1, 2})
print(B) # frozenset({0, 1, 2})

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

Top comments (0)