DEV Community

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

Posted on • Edited on

Shallow copy & Deep copy in Python (5)

Buy Me a Coffee

*Memo for shallow and deep copy:

*Memo for shallow and deep copy:


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


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

*Memo:

  • The 2D set with a 1D iterator can be shallow-copied and deep-copied.
  • A set can have the hashable types of elements like frozenset, tuple, iterator, etc but cannot have the unhashable types of elements like set, list, dict, etc.
  • Different iterators are referred to if 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 iterator.
  • is keyword can check if A and B refer to the same outer set and/or inner iterator.

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

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

print(A) # {<list_iterator object at 0x000001F95F9C6410>}
print(B) # {<list_iterator object at 0x000001F95F9C6410>}

print(A is B)
# True

print(B.pop()) # <list_iterator object at 0x000001F95F9C6410>
print(A)       # set()
print(B)       # set()
Enter fullscreen mode Exit fullscreen mode

<Shallow copy>:

*Memo:

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

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

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

print(A) # {<list_iterator object at 0x000001F9606954E0>}
print(B) # {<list_iterator object at 0x000001F9606954E0>}

print(A is B)
# False

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

print(A) # <list_iterator object at 0x000001F9606954E0>
print(B) # <list_iterator object at 0x000001F9606954E0>

print(A is B)
# True

print(next(A)) # 0
print(next(B)) # 1
print(next(A)) # 2
print(next(B)) # StopIteration:
Enter fullscreen mode Exit fullscreen mode

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

import copy

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

print(A) # {<list_iterator object at 0x000001F95F9CD510>}
print(B) # {<list_iterator object at 0x000001F95F9CD510>}

print(A is B)
# False

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

print(A) # <list_iterator object at 0x000001F95F9CD510>
print(B) # <list_iterator object at 0x000001F95F9CD510>

print(A is B)
# True

print(next(A)) # 0
print(next(B)) # 1
print(next(A)) # 2
print(next(B)) # StopIteration:
Enter fullscreen mode Exit fullscreen mode

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

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

print(A) # {<list_iterator object at 0x000001F9605E3730>}
print(B) # {<list_iterator object at 0x000001F9605E3730>}

print(A is B)
# False

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

print(A) # <list_iterator object at 0x000001F9605E3730>
print(B) # <list_iterator object at 0x000001F9605E3730>

print(A is B)
# True

print(next(A)) # 0
print(next(B)) # 1
print(next(A)) # 2
print(next(B)) # StopIteration:
Enter fullscreen mode Exit fullscreen mode

<Deep copy>:

*Memo:

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

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

*Memo:

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

A = {iter([0, 1, 2])}
B = deepcopy(A)

print(A) # {<list_iterator object at 0x000001F96065DE40>}
print(B) # {<list_iterator object at 0x000001F960695CC0>}

print(A is B)
# False

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

print(A) # <list_iterator object at 0x000001F96065DE40>
print(B) # <list_iterator object at 0x000001F960695CC0>

print(A is B)
# False

print(next(A)) # 0
print(next(B)) # 0
print(next(A)) # 1
print(next(B)) # 1
print(next(A)) # 2
print(next(B)) # 2

print(next(A))
print(next(B))
# StopIteration:
Enter fullscreen mode Exit fullscreen mode

set.copy() and copy() can deep-copy the 2D set with a 1D iterator, shallow-copying the outer set and inner iterator as shown below:

import copy

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

print(A) # {<list_iterator object at 0x000001F9604F6410>}
print(B) # {<list_iterator object at 0x000001F9604F6410>}

print(A is B)
# False

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

print(A) # <list_iterator object at 0x000001F9604F7910>
print(B) # <list_iterator object at 0x000001F9605E3190>

print(A is B)
# False

print(next(A)) # 0
print(next(B)) # 0
print(next(A)) # 1
print(next(B)) # 1
print(next(A)) # 2
print(next(B)) # 2

print(next(A))
print(next(B))
# StopIteration:
Enter fullscreen mode Exit fullscreen mode

set() and copy.copy() can deep-copy the 2D set with a 1D iterator, shallow-copying the outer set and inner iterator as shown below:

import copy

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

print(A) # {<list_iterator object at 0x000001F95F9BDF90>}
print(B) # {<list_iterator object at 0x000001F95F9BDF90>}

print(A is B)
# False

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

print(A) # <list_iterator object at 0x000001F96065DFF0>
print(B) # <list_iterator object at 0x000001F96065D360>

print(A is B)
# False

print(next(A)) # 0
print(next(B)) # 0
print(next(A)) # 1
print(next(B)) # 1
print(next(A)) # 2
print(next(B)) # 2

print(next(A))
print(next(B))
# StopIteration:
Enter fullscreen mode Exit fullscreen mode

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

import copy

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

print(A) # {<list_iterator object at 0x0000029DDF277B20>}
print(B) # {<list_iterator object at 0x0000029DE0049210>}

print(A is B)
# False

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

print(A) # <list_iterator object at 0x0000029DDF277B20>
print(B) # <list_iterator object at 0x0000029DE0049210>

print(A is B)
# False

A = next(A)
B = next(B)

print(A) # <list_iterator object at 0x000002451219DC60>
print(B) # <list_iterator object at 0x000002451219E140>

print(A is B)
# False

print(next(A)) # 0
print(next(B)) # 0
print(next(A)) # 1
print(next(B)) # 1
print(next(A)) # 2
print(next(B)) # 2

print(next(A))
print(next(B))
# StopIteration:
Enter fullscreen mode Exit fullscreen mode

Top comments (0)