Shallow Copy and Deep Copy in Python

In Python, when we create a copy of an object, we can either create a shallow copy or a deep copy. Both shallow copy and deep copy are used to create a new object with the same values as the original object, but there is a significant difference between the two.

A shallow copy creates a new object, but it does not create a new copy of the object’s data. Instead, it creates a new reference to the original object’s data. In other words, a shallow copy points to the same data as the original object. If the data is mutable (i.e., it can be changed), changes made to the original object’s data will be reflected in the shallow copy, and vice versa. To create a shallow copy in Python, we can use the copy() method.

Here’s an example of creating a shallow copy of a list in Python:

original_list = [1, 2, 3]
shallow_copy = original_list.copy()

original_list[0] = 100

print(original_list)  # Output: [100, 2, 3]
print(shallow_copy)   # Output: [1, 2, 3]

As you can see, changing the first element of the original list did not affect the shallow copy.

On the other hand, a deep copy creates a new object and a new copy of the object’s data. In other words, a deep copy creates a completely independent copy of the original object’s data. If the data is mutable, changes made to the original object’s data will not be reflected in the deep copy, and vice versa. To create a deep copy in Python, we can use the deepcopy() method from the copy module.

Here’s an example of creating a deep copy of a list in Python:

import copy

original_list = [1, 2, 3]
deep_copy = copy.deepcopy(original_list)

original_list[0] = 100

print(original_list)  # Output: [100, 2, 3]
print(deep_copy)      # Output: [1, 2, 3]

As you can see, changing the first element of the original list did not affect the deep copy.

Copying Arbitrary Python Objects:

Copying arbitrary Python objects involves creating a new object that is a copy of the original object, but the copying process depends on the object’s properties and behavior. In Python, we can use either shallow copy or deep copy to copy objects, but in some cases, we may need to implement our own copy method.

For built-in data types like lists, dictionaries, and tuples, we can use the copy() method for shallow copy and the deepcopy() method from the copy module for deep copy. However, for user-defined objects, we need to implement the __copy__() and __deepcopy__() methods.

The __copy__() method is called when a shallow copy of an object is created using the copy() method. The method should return a new object with the same properties as the original object.

The __deepcopy__() method is called when a deep copy of an object is created using the deepcopy() method. The method should return a new object with the same properties as the original object and its child objects.

Here’s an example of creating a copy of a custom object in Python:

import copy

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return f"{self.name} ({self.age})"

    def __copy__(self):
        return Person(self.name, self.age)

    def __deepcopy__(self, memo):
        return Person(copy.deepcopy(self.name, memo), copy.deepcopy(self.age, memo))

# Creating an instance of the Person class
person1 = Person("Alice", 25)

# Shallow copy
person2 = copy.copy(person1)

# Deep copy
person3 = copy.deepcopy(person1)

# Modifying the original object
person1.name = "Bob"
person1.age = 30

# Output
print(person1) # Output: Bob (30)
print(person2) # Output: Alice (30)
print(person3) # Output: Alice (25)

In the above example, we defined the __copy__() and __deepcopy__() methods for the Person class. The __copy__() method returns a new Person object with the same name and age as the original object. The __deepcopy__() method uses the copy.deepcopy() method to create new copies of the name and age attributes.

We then created an instance of the Person class and used both the copy() and deepcopy() methods to create copies of the object. We then modified the original object’s attributes and observed that the shallow copy had the modified attribute, while the deep copy had the original attribute values.

In the above example, we defined the __copy__() and __deepcopy__() methods for the Person class. The __copy__() method returns a new Person object with the same name and age as the original object. The __deepcopy__() method uses the copy.deepcopy() method to create new copies of the name and age attributes.

We then created an instance of the Person class and used both the copy() and deepcopy() methods to create copies of the object. We then modified the original object’s attributes and observed that the shallow copy had the modified attribute, while the deep copy had the original attribute values.

Points to Remember:

Here are some key points to remember about copying in Python:

  1. Python provides two types of copy: shallow copy and deep copy.
  2. Shallow copy creates a new object but does not create a new copy of the object’s data. Instead, it creates a new reference to the original object’s data.
  3. Deep copy creates a new object and a new copy of the object’s data. In other words, it creates a completely independent copy of the original object’s data.
  4. For built-in data types like lists, dictionaries, and tuples, we can use the copy() method for shallow copy and the deepcopy() method from the copy module for deep copy.
  5. For user-defined objects, we need to implement the __copy__() and __deepcopy__() methods.
  6. The __copy__() method is called when a shallow copy of an object is created using the copy() method. The method should return a new object with the same properties as the original object.
  7. The __deepcopy__() method is called when a deep copy of an object is created using the deepcopy() method. The method should return a new object with the same properties as the original object and its child objects.
  8. Changes made to the original object’s data will be reflected in the shallow copy, and vice versa. Changes made to the original object’s data will not be reflected in the deep copy, and vice versa.
  9. Copying is important for avoiding unintended side effects and preserving the integrity of the original data.