LearnFrenzy
Sign in Take a free test

Python Programming interview · Set 8 of 19

Object-Oriented Programming in Python

  • 7 follow-up questions
  • 4 key points
  • Code examples
Test yourself

Python OOP, the Python way

Know how attributes are looked up (instance, class, MRO), how to extend parents with super(), and how Python prefers conventions, properties and duck typing over strict access control.

  • ClassesInstance vs class attributes and dunder methods.
  • Inheritancesuper(), MRO and abstract base classes.
  • DesignEncapsulation, duck typing and composition.

Python supports full object-oriented programming, but in its own relaxed style: no access modifiers, duck typing instead of interfaces, and multiple inheritance with a clear lookup order. Interviewers check that you can design clean classes and explain how Python finds attributes and methods.

1. Class attributes vs instance attributes — what is the trap?

Class attributes are shared by all instances; instance attributes belong to one object. The trap: a mutable class attribute such as a list is shared, so one object's changes appear in every other object. Initialise per-object state in __init__.

class Team:
    members = []                 # shared by ALL teams — bug

    def __init__(self, name):
        self.name = name
        self.players = []        # one list per team — correct

a, b = Team("A"), Team("B")
a.members.append("Asha")
print(b.members)                 # ['Asha'] — surprise!

2. How does inheritance work and what does super() do?

A subclass inherits attributes and methods and can override them. super() returns a proxy to the next class in the method resolution order, so you can extend a parent's behaviour instead of copying it. Always call super().__init__() when the parent needs initialising.

class Account:
    def __init__(self, owner, balance=0):
        self.owner, self.balance = owner, balance

    def withdraw(self, amount):
        if amount > self.balance:
            raise ValueError("Insufficient balance")
        self.balance -= amount

class SavingsAccount(Account):
    def __init__(self, owner, balance=0, rate=0.04):
        super().__init__(owner, balance)
        self.rate = rate

    def add_interest(self):
        self.balance += self.balance * self.rate

3. What is the MRO and how does Python resolve multiple inheritance?

The Method Resolution Order is the sequence of classes Python searches for an attribute. It is computed with the C3 linearisation algorithm: children before parents, and the left-to-right order of bases is kept. This solves the diamond problem — the shared base appears once, at the end. Inspect it with ClassName.__mro__.

class A:
    def hello(self): return "A"
class B(A):
    def hello(self): return "B"
class C(A):
    def hello(self): return "C"
class D(B, C):
    pass

print(D().hello())                       # B
print([k.__name__ for k in D.__mro__])   # ['D', 'B', 'C', 'A', 'object']

4. How do you achieve encapsulation in Python?

Python has no private keyword; it relies on convention. A single underscore (_balance) means “internal, do not touch”. A double underscore (__pin) triggers name mangling to _ClassName__pin, which prevents accidental clashes in subclasses. Expose controlled access with @property and validation in setters.

class Wallet:
    def __init__(self):
        self._balance = 0

    @property
    def balance(self):
        return self._balance

    @balance.setter
    def balance(self, value):
        if value < 0:
            raise ValueError("Balance cannot be negative")
        self._balance = value

5. What are abstract base classes?

An abstract base class (from abc) defines methods subclasses must implement. You cannot instantiate it, and a subclass that forgets an abstract method fails at creation time — catching mistakes early. Use ABCs for plugin-style designs such as payment gateways or storage backends.

from abc import ABC, abstractmethod

class PaymentGateway(ABC):
    @abstractmethod
    def charge(self, amount: float) -> str: ...

class Razorpay(PaymentGateway):
    def charge(self, amount):
        return f"razorpay-txn-{amount}"

# PaymentGateway()  -> TypeError: Can't instantiate abstract class

6. What is duck typing and how does it relate to polymorphism?

“If it walks like a duck and quacks like a duck, it is a duck.” Python cares whether an object has the methods you call, not its declared type. Any object with a read() method can be used where a file is expected. typing.Protocol lets type checkers verify this structural typing.

from typing import Protocol

class Notifier(Protocol):
    def send(self, to: str, text: str) -> None: ...

class Email:
    def send(self, to, text): print(f"email {to}: {text}")

class Sms:
    def send(self, to, text): print(f"sms {to}: {text}")

def alert(n: Notifier):
    n.send("Asha", "Interview at 10 AM")

for channel in (Email(), Sms()):
    alert(channel)          # polymorphism without a shared base class

7. Composition vs inheritance — which do you prefer?

Inheritance models an “is-a” relationship; composition models “has-a” by holding other objects. Prefer composition: it keeps classes small, avoids deep fragile hierarchies and lets you swap parts at runtime. Use inheritance for genuine specialisation or framework hooks.

class Engine:
    def start(self): return "engine on"

class Car:
    def __init__(self, engine: Engine):
        self.engine = engine          # has-a
    def drive(self):
        return self.engine.start() + ", driving"

print(Car(Engine()).drive())

8. What do __str__ and __repr__ do?

__repr__ is the unambiguous developer view, ideally valid code to recreate the object — shown in the console, logs and debuggers. __str__ is the friendly user view used by print(). Always implement __repr__; add __str__ when the user-facing text differs.

class Order:
    def __init__(self, id, total):
        self.id, self.total = id, total
    def __repr__(self):
        return f"Order(id={self.id!r}, total={self.total!r})"
    def __str__(self):
        return f"Order #{self.id} — ₹{self.total}"

o = Order(1042, 899)
print(o)          # Order #1042 — ₹899
print([o])        # [Order(id=1042, total=899)]

Remember

Key points

  • Mutable class attributes are shared

    Create per-object state in __init__.

  • super() follows the MRO

    Not simply “the parent class”.

  • Conventions over keywords

    _internal, __mangled and @property.

  • Prefer composition

    Small classes you can combine and swap.

Interview drill

Follow-up questions

What the interviewer asks after your first answer. Turn on practice mode, answer each one aloud, then reveal.

  1. 1 What is the difference between __new__ and __init__? Advanced

    __new__ creates and returns the instance (used for immutable types and singletons); __init__ initialises the already-created instance.

  2. 2 What is a metaclass? Advanced

    The class of a class — it controls how classes are created. type is the default. Frameworks such as Django ORM use them; in application code, class decorators or __init_subclass__ are usually simpler.

  3. 3 How do you implement a singleton in Python? Intermediate

    The simplest way is a module-level instance (modules are imported once). Alternatively override __new__ to return a cached instance.

  4. 4 What is a mixin? Intermediate

    A small class that adds one capability (such as JsonMixin.to_json()) to be combined through multiple inheritance; it is not meant to stand alone.

  5. 5 How do you make objects comparable and sortable? Intermediate

    Implement __eq__ and __lt__ and add @functools.total_ordering, or use @dataclass(order=True).

  6. 6 What does isinstance() check compared with type()? Basic

    isinstance(obj, Cls) respects inheritance (a subclass instance passes); type(obj) is Cls matches only the exact class. Prefer isinstance.

  7. 7 What are class methods used for in real code? Basic

    Alternative constructors such as User.from_dict(data) or Date.today(); they receive the class, so subclasses get the right type.

Preparing with friends?

Share this page with your study group or placement batch.

Popular