Noticed that when a passed parameter is an object, making a copy of the parameter and changing the copy attribute's value also changes the original attribute's value (Shallow Copy). However, when the passed object is a simple variable, creating and changing the copy's value does not change the original (Deep Copy).
Example:
1. Variable passed as argument
def increment(x):
    y = x
    y += 1
    print(f'{x=}, {y=}')
increment(2)
Out: 
x=2, y=3
x did not change when it's copy y was incremented
2. Object passed as argument
class Node:
    def __init__(self, val=0):
        self.val = val
def increment(x):
    y = x
    y.val += 1
    print(f'{x.val=}, {y.val=}')
increment(Node(2))
Out: 
x.val=3, y.val=3
x.val was also incremented when copy y.val was incremented.
What is the best (computationally time-efficient) way to go about creating a deep copy of the object? Can I write the class in a way such that I don't have to make any changes in the function code?
 
    