Top Python 3.x Interview Questions

author image Hirely
at 10 Jan, 2025

Question: What is the difference between a shallow copy and a deep copy in Python?

Answer:

In Python, shallow copy and deep copy refer to how objects are copied, particularly when those objects contain other nested objects (e.g., lists of lists, dictionaries with lists as values, etc.).

1. Shallow Copy

A shallow copy creates a new object, but it does not create copies of nested objects inside the original object. Instead, it simply references the original nested objects. Therefore, the shallow copy will have a new top-level container, but the nested objects will still be shared with the original object.

Key Points:
  • The top-level container is copied.
  • The nested objects (inside the container) are not copied, they are just referenced.
  • Modifying the nested objects in the shallow copy will affect the original object (and vice versa) because they both refer to the same nested objects.
Example of Shallow Copy:
import copy

# Original object
original_list = [[1, 2, 3], [4, 5, 6]]

# Shallow copy
shallow_copy = copy.copy(original_list)

# Modify a nested element
shallow_copy[0][0] = 99

print("Original List:", original_list)
print("Shallow Copy:", shallow_copy)

Output:

Original List: [[99, 2, 3], [4, 5, 6]]
Shallow Copy: [[99, 2, 3], [4, 5, 6]]

Explanation: After modifying shallow_copy[0][0], the original_list[0][0] was also modified because both the original list and the shallow copy reference the same nested list [1, 2, 3].


2. Deep Copy

A deep copy creates a completely new object and also recursively copies all the nested objects inside the original object. As a result, the deep copy is fully independent of the original object. Changes made to the deep copy do not affect the original object, and vice versa.

Key Points:
  • The top-level container is copied.
  • Nested objects are recursively copied, meaning the deep copy creates a new independent copy of all nested objects.
  • Modifying any part of the deep copy will not affect the original object.
Example of Deep Copy:
import copy

# Original object
original_list = [[1, 2, 3], [4, 5, 6]]

# Deep copy
deep_copy = copy.deepcopy(original_list)

# Modify a nested element
deep_copy[0][0] = 99

print("Original List:", original_list)
print("Deep Copy:", deep_copy)

Output:

Original List: [[1, 2, 3], [4, 5, 6]]
Deep Copy: [[99, 2, 3], [4, 5, 6]]

Explanation: After modifying deep_copy[0][0], the original_list remains unchanged because the deep copy created an independent copy of the entire object structure.


Summary of Differences:

FeatureShallow CopyDeep Copy
Top-level objectCopied to a new object.Copied to a new object.
Nested objectsReferenced (not copied).Copied recursively (deeply).
Effect of modificationModifying nested objects affects both the original and the copy.Modifying nested objects only affects the copy.
Method of creationcopy.copy()copy.deepcopy()

When to Use:

  • Shallow Copy: Useful when you want to create a copy of the outer object but are okay with sharing the inner objects (i.e., nested objects) between the original and the copy. This is more memory efficient.

  • Deep Copy: Necessary when you need an independent copy of an object, including all nested objects, and you want changes to the copy to not affect the original object. This is typically used when the object contains complex nested structures (e.g., lists of dictionaries or lists of lists).

Question: What is the self keyword in Python?

Answer:

In Python, self is a reference to the current instance of the class. It is used in instance methods within a class to refer to the object that is calling the method. It is essentially a way for an object to access its own attributes and methods.

self is not a reserved keyword in Python, but it is a strong convention that is universally used. You can technically use any other name instead of self, but doing so would break standard Python conventions and make the code harder to read and understand for other developers.


Key Points:

  1. Refers to the Current Object: The self parameter in instance methods refers to the specific instance of the class on which the method is being called. This allows you to access the object’s attributes and methods from within the class.

  2. Used to Access Instance Variables and Methods: You use self to reference attributes or call other methods of the current object within the class.

  3. Must Be the First Parameter: In instance methods, self must always be the first parameter, even though it’s not passed explicitly when calling the method. Python implicitly passes the instance as the first argument when the method is invoked.


Example of self in Action:

class Dog:
    # Constructor method to initialize the object
    def __init__(self, name, age):
        self.name = name  # self.name refers to the instance variable 'name'
        self.age = age    # self.age refers to the instance variable 'age'

    # Instance method that uses self
    def bark(self):
        print(f"{self.name} says Woof!")

    def display_age(self):
        print(f"{self.name} is {self.age} years old.")

# Create an instance of the Dog class
my_dog = Dog("Buddy", 3)

# Accessing instance methods and attributes using self
my_dog.bark()            # Buddy says Woof!
my_dog.display_age()     # Buddy is 3 years old.

In the code above:

  • The __init__ method uses self to assign the name and age attributes to the instance of the Dog class.
  • The bark and display_age methods also use self to access these instance attributes and methods.
  • When calling my_dog.bark() or my_dog.display_age(), Python implicitly passes my_dog as the self parameter to these methods.

How self Works in Method Calls:

  • When you call an instance method like my_dog.bark(), Python implicitly sends the my_dog object as the first argument to the bark() method, i.e., bark(self) becomes bark(my_dog). This allows the method to access and modify the my_dog object’s attributes and behavior.

Why self is Important:

  1. Distinguishing Instance Variables: It allows you to differentiate between instance variables and local variables or parameters inside the methods. For example, when you define self.name, you’re telling Python that this is an instance variable, not a local variable.

  2. Accessing Instance Methods: self is used to call other instance methods from within a class. Without self, you would not be able to refer to the instance of the class.


Common Misunderstandings:

  1. self is not a keyword: You can technically replace self with another name, but it’s a convention that should not be altered. It’s part of the Python style guide (PEP 8) to use self consistently.

  2. self is not automatically passed when calling a method: Although you must include self as the first parameter in the method definition, when calling the method (e.g., my_dog.bark()), you don’t pass self explicitly. Python automatically passes the instance (in this case, my_dog) as self.


Example with Multiple Instances:

class Car:
    def __init__(self, brand, model, year):
        self.brand = brand
        self.model = model
        self.year = year

    def get_info(self):
        return f"{self.year} {self.brand} {self.model}"

# Create multiple instances of the Car class
car1 = Car("Toyota", "Corolla", 2020)
car2 = Car("Honda", "Civic", 2021)

# Access instance-specific information
print(car1.get_info())  # 2020 Toyota Corolla
print(car2.get_info())  # 2021 Honda Civic

In this example:

  • self ensures that each car object (car1 and car2) has its own attributes (brand, model, year) and the correct information is returned when get_info() is called for each instance.

Summary:

  • self is a reference to the current instance of a class in Python.
  • It is used to access instance variables and methods within a class.
  • self must always be the first parameter in an instance method, but you don’t explicitly pass it when calling the method—Python does it automatically.
  • self is crucial for object-oriented programming in Python, allowing you to write code that works with individual instances of a class.

Read More

If you can’t get enough from this article, Aihirely has plenty more related information, such as Python 3.x interview questions, Python 3.x interview experiences, and details about various Python 3.x job positions. [Click here](https://www.aihirely.com/tag/Python 3.x) to check it out.

Related Posts

Trace Job opportunities

Hirely, your exclusive interview companion, empowers your competence and facilitates your interviews.

Get Started Now