Skip to content

Python OOP

Amin Zamani edited this page May 2, 2023 · 2 revisions

Here are some answers to the OOP interview questions:

1. What is object-oriented programming, and what are its advantages?

Object-oriented programming (OOP) is a programming paradigm that uses objects to represent real-world entities. The main advantages of OOP are code reuse, maintainability, and extensibility.

2. What are classes in Python, and how are they used?

Classes in Python are templates for creating objects. They define the attributes (variables) and methods (functions) of the objects. Classes are used to create new instances of objects.

3. What is inheritance in Python, and how is it implemented?

Inheritance is a feature of OOP that allows a new class to be based on an existing class. The new class, known as the subclass, inherits all the attributes and methods of the existing class, known as the superclass. In Python, inheritance is implemented by specifying the name of the superclass in the subclass definition.

4. What is polymorphism in Python, and how is it achieved?

Polymorphism is a feature of OOP that allows objects of different classes to be treated as if they are of the same class. In Python, polymorphism is achieved through method overriding and method overloading.

5. What is encapsulation in Python, and how is it achieved?

Encapsulation is a feature of OOP that allows data and methods to be hidden from other objects. In Python, encapsulation is achieved through the use of access modifiers such as public, private, and protected.

6. What is the difference between an instance and a class in Python?

A class in Python is a template for creating objects, while an instance is a specific object created from a class.

7. What is the difference between a method and a function in Python?

A method in Python is a function that is defined inside a class, and is called on an instance of the class. A function in Python is a standalone block of code that can be called independently of any class.

8. What is the difference between composition and inheritance in Python?

Composition is a design pattern in which objects contain other objects as attributes, while inheritance is a mechanism for creating new classes based on existing classes. Composition allows for more flexibility and less coupling than inheritance.

9. What is the difference between public, private, and protected access modifiers in Python?

Public variables and methods can be accessed from anywhere in the program, while private variables and methods can only be accessed from within the class. Protected variables and methods can be accessed from within the class and its subclasses.

10. What are abstract classes and interfaces in Python, and how are they used?

Abstract classes and interfaces are used to define a common set of methods that must be implemented by any class that inherits from them. Abstract classes can also define attributes and methods that all inheriting classes must have.

11. What is method overloading in Python, and is it supported?

Method overloading is the ability to define multiple methods with the same name but different parameters. Python does not support method overloading in the traditional sense, but it can be simulated using default arguments or variable-length argument lists.

12. What is method overriding in Python, and how is it achieved?

Method overriding is the ability to provide a different implementation for a method in a subclass than the one provided by the superclass. This is achieved by defining a method with the same name and parameters in the subclass as the one in the superclass.

13. What is a decorator in Python, and how is it used in OOP?

A decorator in Python is a function that takes another function as input and extends or modifies its behavior. Decorators can be used in OOP to modify the behavior of methods or classes.

14. What is a generator in Python, and how can it be used in OOP?

A generator in Python is a type of iterator that produces a sequence of values on-the-fly, rather than storing them all in memory at once. Generators are useful in OOP because they can be used to implement custom iterators that generate values based on some internal logic or state.

For example, a class that represents a sequence of Fibonacci numbers could use a generator to produce the next number in the sequence each time its next() method is called:

class Fibonacci:
    def __init__(self):
        self.a = 0
        self.b = 1

    def __iter__(self):
        return self

    def __next__(self):
        result = self.a
        self.a, self.b = self.b, self.a + self.b
        return result

In this example, the Fibonacci class implements the iterator protocol by defining the iter() and next() methods. The iter() method simply returns the object itself, since the class is also an iterator. The next() method generates the next Fibonacci number in the sequence by keeping track of the current values of self.a and self.b, and returning the current value of self.a before updating the values for the next iteration.

15. What is a class method in Python, and how is it different from an instance method?

A class method in Python is a method that is bound to the class and not the instance of the class. This means that it can be called on the class itself, rather than on an instance of the class. A class method is defined using the @classmethod decorator, and takes the class as its first argument, conventionally named cls.

Here's an example of a class method in Python:

class MyClass:
    x = 0

    @classmethod
    def increment(cls):
        cls.x += 1

In this example, the increment() method is a class method, since it takes the class (cls) as its first argument. This method increments the class variable x by one each time it is called. The class method can be called on the class itself, rather than on an instance of the class:

MyClass.increment()
print(MyClass.x)  # Output: 1

An instance method, on the other hand, is a method that is bound to the instance of the class, rather than to the class itself. This means that it can be called on an instance of the class, but not on the class itself. An instance method is defined without the @classmethod decorator, and takes the instance as its first argument, conventionally named self.

Here's an example of an instance method in Python:

class MyClass:
    def __init__(self):
        self.x = 0

    def increment(self):
        self.x += 1

In this example, the increment() method is an instance method, since it takes the instance (self) as its first argument. This method increments the instance variable x by one each time it is called. The instance method can be called on an instance of the class:

my_object = MyClass()
my_object.increment()
print(my_object.x)  # Output: 1

16. What is inheritance in Python, and how is it useful in OOP?

Inheritance in Python is a mechanism that allows one class (the child or subclass) to inherit properties and behavior from another class (the parent or superclass). The child class can then add or override properties and behavior as needed.

Inheritance is useful in OOP because it allows for code reuse and can simplify the implementation of related classes. For example, if you have a class that represents a generic vehicle, you could define properties and behavior that are common to all vehicles, such as a make and model, number of wheels, and a method for starting the engine. You could then define more specific vehicle classes, such as a car or a motorcycle, that inherit from the generic vehicle class and add or override properties and behavior as needed.

Here's an example of inheritance in Python:

class Vehicle:
    def __init__(self, make, model, num_wheels):
        self.make = make
        self.model = model
        self.num_wheels = num_wheels

    def start_engine(self):
        print("Starting engine...")

class Car(Vehicle):
    def __init__(self, make, model):
        super().__init__(make, model, 4)

    def drive(self):
        print("Driving the car...")

class Motorcycle(Vehicle):
    def __init__(self, make, model):
        super().__init__(make, model, 2)

    def ride(self):
        print("Riding the motorcycle...")

In this example, the Vehicle class is the parent class, and the Car and Motorcycle classes are child classes that inherit from it. The Car and Motorcycle classes override the init() method to set the number of wheels appropriately, and define additional methods for driving or riding, respectively. When an instance of the Car or Motorcycle class is created, it inherits the properties and behavior of the Vehicle class as well.

17. What is polymorphism in Python, and how does it relate to inheritance?

Polymorphism in Python is the ability of an object to take on many forms or to have multiple behaviors depending on the context in which it is used. In other words, different objects can respond to the same message (method call) in different ways. Polymorphism is closely related to inheritance in Python, because it allows objects of different classes that inherit from the same superclass to be treated as if they are of the same class.

Here's an example of polymorphism in Python:

class Animal:
    def __init__(self, name):
        self.name = name

    def make_sound(self):
        pass

class Dog(Animal):
    def make_sound(self):
        return "Woof!"

class Cat(Animal):
    def make_sound(self):
        return "Meow!"

class Bird(Animal):
    def make_sound(self):
        return "Chirp!"

def animal_sounds(animals):
    for animal in animals:
        print(animal.name + " says " + animal.make_sound())

dog = Dog("Fido")
cat = Cat("Whiskers")
bird = Bird("Polly")

animal_sounds([dog, cat, bird])

In this example, the Animal class is the superclass, and the Dog, Cat, and Bird classes are subclasses that inherit from it. Each subclass defines its own implementation of the make_sound() method, so that each instance of the subclass can make a different sound. The animal_sounds() function takes a list of Animal objects as an argument, and calls the make_sound() method on each one. Because each subclass implements the make_sound() method differently, each Animal object will make a different sound when the function is called. This demonstrates the polymorphic behavior of the Animal objects, because they can all respond to the same message (make_sound()) in different ways.

18. What is method overriding in Python, and how does it relate to inheritance?

Method overriding in Python is the process of defining a new implementation for an inherited method in a subclass, in order to modify or extend its behavior. When a method is overridden in a subclass, the new implementation in the subclass takes precedence over the inherited implementation in the superclass.

Method overriding is related to inheritance in Python because it allows a subclass to inherit behavior from its superclass, but modify or extend that behavior as needed. This can be useful for customizing the behavior of a class without having to rewrite the entire implementation from scratch.

Here's an example of method overriding in Python:

class Animal:
    def move(self):
        print("This animal moves.")

class Dog(Animal):
    def move(self):
        print("This dog walks on four legs.")

class Snake(Animal):
    def move(self):
        print("This snake slithers on its belly.")

dog = Dog()
snake = Snake()

dog.move()   # Output: This dog walks on four legs.
snake.move() # Output: This snake slithers on its belly.

In this example, the Animal class defines a generic move() method that simply prints a message indicating that the animal moves. The Dog and Snake classes are subclasses of Animal that override the move() method with their own implementation that reflects the specific way that each animal moves. When an instance of the Dog or Snake class calls the move() method, the new implementation in the subclass takes precedence over the inherited implementation in the Animal superclass, so the output reflects the specific way that each animal moves.

19. What is method overloading in Python, and does Python support it?

Method overloading is the ability to define multiple methods with the same name but different parameters in a class. This allows the programmer to provide a more intuitive interface to the class, by allowing the same method name to be used for different operations based on the type or number of arguments passed to it.

However, method overloading is not directly supported in Python, because Python is dynamically typed and uses duck typing, which means that the type of an object is determined by its behavior rather than its class. In Python, you can define a function with the same name as an existing function, but the new function will simply replace the old function in the namespace.

Instead of method overloading, Python uses default arguments and variable-length argument lists to achieve similar functionality. By defining default arguments or using variable-length argument lists, you can create a function that can take different numbers or types of arguments, depending on the needs of the program.

Here's an example of using default arguments in Python to achieve similar functionality to method overloading:

class Math:
    def add(self, x, y=0, z=0):
        return x + y + z

math = Math()

print(math.add(1))        # Output: 1
print(math.add(1, 2))     # Output: 3
print(math.add(1, 2, 3))  # Output: 6

In this example, the Math class defines an add() method that takes one, two, or three arguments, depending on how it is called. By defining default arguments for y and z, the method can be called with one, two, or three arguments, and will behave correctly in each case. This provides similar functionality to method overloading, by allowing the same method name to be used for different operations based on the number of arguments passed to it.

20. What is a class variable in Python, and how is it different from an instance variable?

A class variable in Python is a variable that is defined in a class and shared by all instances of the class. It is also known as a static variable, because its value is shared among all instances of the class and does not change unless explicitly modified.

In contrast, an instance variable is a variable that is defined in an instance of a class and is unique to that instance. Each instance of the class can have its own value for an instance variable.

Here's an example of a class variable in Python:

class Employee:
    # Class variable
    company = "ABC Inc."
    
    def __init__(self, name, age):
        # Instance variables
        self.name = name
        self.age = age

emp1 = Employee("John", 30)
emp2 = Employee("Jane", 25)

print(emp1.company) # Output: ABC Inc.
print(emp2.company) # Output: ABC Inc.

Employee.company = "XYZ Inc."

print(emp1.company) # Output: XYZ Inc.
print(emp2.company) # Output: XYZ Inc.

In this example, the Employee class defines a class variable named company, which is shared by all instances of the class. When we create two instances of the Employee class, emp1 and emp2, both instances share the same value for the company variable. When we change the value of the company variable for the class, the change is reflected in all instances of the class.

Python

Python Essentials 1 (PCEP)

Introduction to Python and computer programming

Data types, variables, basic I/O operations, and basic operators

Boolean values, conditional execution, loops, lists and list processing, logical and bitwise operations

Clean Code

Algorithms

Django

Django Rest Framework

API

pip

SQLAlchemy

FastAPI

Pytest

TDD

Git

Linux

Docker

Python Testing

Interview Questions

Clone this wiki locally