Top Python 3.x Interview Questions
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:
Feature | Shallow Copy | Deep Copy |
---|---|---|
Top-level object | Copied to a new object. | Copied to a new object. |
Nested objects | Referenced (not copied). | Copied recursively (deeply). |
Effect of modification | Modifying nested objects affects both the original and the copy. | Modifying nested objects only affects the copy. |
Method of creation | copy.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:
-
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. -
Used to Access Instance Variables and Methods: You use
self
to reference attributes or call other methods of the current object within the class. -
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 usesself
to assign thename
andage
attributes to the instance of theDog
class. - The
bark
anddisplay_age
methods also useself
to access these instance attributes and methods. - When calling
my_dog.bark()
ormy_dog.display_age()
, Python implicitly passesmy_dog
as theself
parameter to these methods.
How self
Works in Method Calls:
- When you call an instance method like
my_dog.bark()
, Python implicitly sends themy_dog
object as the first argument to thebark()
method, i.e.,bark(self)
becomesbark(my_dog)
. This allows the method to access and modify themy_dog
object’s attributes and behavior.
Why self
is Important:
-
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. -
Accessing Instance Methods:
self
is used to call other instance methods from within a class. Withoutself
, you would not be able to refer to the instance of the class.
Common Misunderstandings:
-
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 useself
consistently. -
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 passself
explicitly. Python automatically passes the instance (in this case,my_dog
) asself
.
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
andcar2
) has its own attributes (brand
,model
,year
) and the correct information is returned whenget_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.
Tags
- Python 3.x
- Python 2.x vs Python 3.x
- Python Decorators
- Shallow Copy
- Deep Copy
- Python Self Keyword
- Staticmethod vs Classmethod
- Python Memory Management
- Python Generators
- Python Yield
- List Comprehensions
- Python Data Types
- Python with Statement
- Python Exception Handling
- Global Interpreter Lock (GIL)
- Python Built in Functions
- Python Lambda Functions
- Python Pass Statement
- Python Modules
- Python Variable Scope
- Python Namespaces
- Python List Methods
- Python Remove vs Del
- Python Functions
- Python Advanced Concepts
- Python Key Features