Your language · Python
Classes and objects (OOP)
Classes, objects, constructors and the four pillars with real examples.
Learn: Classes and objects in Python: the four pillars9 minute read
Object-oriented programming (OOP) means building a program from objects that hold data together with the code that works on it. Python does OOP with fewer rules than Java: there are no access modifiers (keywords such as private that control who can use a member), no interface keyword (a type that lists methods without bodies) and no overloading (several methods with one name and different parameters), and a class may have several parents. Interviewers ask you to explain the four pillars with Python examples, and they check that you understand self, super() and the method resolution order (explained in step 4).
Step 1: classes, objects, __init__ and self
A class is a blueprint, and calling it creates an object (an instance of the class). Python first runs __new__ to create the object and then __init__ to set it up. self is the object itself; Python passes it as the first parameter of every instance method, and you set attributes on it, as in self.driver = driver. Attributes written in the class body are class attributes, shared by every object, much like Java's static fields.
If a subclass defines its own __init__, the parent's __init__ does not run unless you call super().__init__(...). Forgetting that call is a common cause of AttributeError (an error that means the object has no such attribute).
Step 2: the four pillars, the Python way
- Encapsulation (keeping data inside an object and exposing only methods) works by convention. A leading underscore (
self._driver) marks internal parts, two underscores trigger name mangling (Python renames the attribute to avoid clashes), and@propertycontrols reading and writing. - Inheritance:
class LoginPage(BasePage)reuses the parent's code. LoginPage is the subclass (child) and BasePage is the parent class. - Polymorphism (one call, many behaviours) comes from overriding (a subclass replaces a parent method) and from duck typing: any object that has the right method works, with no common parent needed.
- Abstraction (showing what an object does and hiding how) comes from clear public methods and from abstract base classes (ABCs) in the
abcmodule.
from abc import ABC, abstractmethod
class BasePage(ABC):
opened = 0 # class attribute, shared
def __init__(self, name):
self._name = name # internal by convention
BasePage.opened += 1
@abstractmethod
def is_loaded(self): ...
def describe(self):
return f"{self._name} loaded={self.is_loaded()}"
class LoginPage(BasePage):
def __init__(self):
super().__init__("Login")
def is_loaded(self):
return True
class CartPage(BasePage):
def __init__(self, items):
super().__init__("Cart")
self._items = items
def is_loaded(self):
return self._items >= 0
def describe(self): # override and extend
return super().describe() + f" items={self._items}"
for page in [LoginPage(), CartPage(2)]:
print(page.describe())
print("pages opened:", BasePage.opened)
try:
BasePage("x")
except TypeError as e:
print("TypeError:", e)
Login loaded=True Cart loaded=True items=2 pages opened: 2 TypeError: Can't instantiate abstract class BasePage without an implementation for abstract method 'is_loaded'
An abstract base class cannot be created, and neither can a subclass that leaves an abstract method out. The error comes when you create the object, not when you define the class. For interfaces, Python mostly relies on duck typing, and typing.Protocol can describe the expected methods for type checkers (tools that check types before the code runs).
Step 3: overriding, but no overloading
Any method can be overridden, and super().method() calls the next version up. A class holds one attribute per name, so a second method with the same name replaces the first; there is no overloading by parameter list. Default arguments and *args cover that need. Operators can be overloaded through special methods with double underscores (dunder methods) such as __eq__ (for ==), __add__ (for +) and __str__ (for text shown by print).
Step 4: multiple inheritance and the MRO
When a class has several parents, Python searches them in a fixed order called the method resolution order (MRO). The rule: the class itself first, then its parents from left to right, each class only once, and never a parent before its children. super() means "the next class in the MRO", which solves the diamond problem, because a shared parent's method runs only once.
class Base:
def setup(self):
return ["Base"]
class ScreenshotMixin(Base):
def setup(self):
return ["Screenshot"] + super().setup()
class LoggingMixin(Base):
def setup(self):
return ["Logging"] + super().setup()
class CheckoutTest(ScreenshotMixin, LoggingMixin):
pass
print(CheckoutTest().setup())
print([c.__name__ for c in CheckoutTest.__mro__])
['Screenshot', 'Logging', 'Base'] ['CheckoutTest', 'ScreenshotMixin', 'LoggingMixin', 'Base', 'object']
For classes that mostly hold data, @dataclass (a decorator, a label above a class that adds features to it) writes __init__, __repr__ and __eq__ for you, and @dataclass(frozen=True) makes objects read-only and hashable, which suits test data. Prefer composition (a page has a driver) over inheritance unless "X is a Y" is really true.
How to answer in an interview
Define each pillar in one line and point to your framework: "Pages inherit from BasePage and call super().__init__(driver). Locators are underscore attributes, and tests call methods like login_as(user). BasePage is an ABC with an abstract is_loaded. Any driver from our fixture works, which is polymorphism." (A fixture is a pytest function that prepares things for a test, such as a driver.) If asked about overloading, say clearly that Python does not have it and name the alternatives.
Common mistakes
- Forgetting
super().__init__()in a subclass. - Writing
self.count += 1to update a class attribute; it creates an instance attribute instead. - Claiming a single underscore makes an attribute private. It is only a convention.
- Thinking
super()always means the direct parent. It follows the MRO. - Defining
__eq__and then putting the objects in a set; without__hash__they are unhashable.
Recap
__init__ sets up an object and self is that object. Encapsulation is by convention, inheritance reuses code, polymorphism comes from overriding and duck typing, and ABCs give abstraction. There is no overloading. Multiple parents are searched in MRO order, and super() moves to the next class in it.
17 questions0/17 solved
| Status | Question | Difficulty | Asked in |
|---|---|---|---|
| Not started | Overriding or overloading? | Easy | Asked in: Accenture, Capgemini, Infosys +2 |
| Not started | The four OOP pillars in Python with examples | Easy-Medium | Asked in: Accenture, Amazon, Capgemini +7 |
| Pro+ | Overloading versus overriding in Python | Easy-Medium | Asked in: Accenture, Capgemini, Cognizant +3 |
| Pro+ | Abstract classes and interfaces in Python | Medium | Asked in: Accenture, Capgemini, Infosys +2 |
| Pro+ | Abstraction versus encapsulation in Python | Medium | Asked in: Capgemini, Coupa, HCLTech |
| Pro+ | Multiple inheritance, the diamond problem and the MRO | Medium | Asked in: Accenture, TCS |
| Pro+ | super() in a diamond | Medium | Asked in: Accenture, TCS |
| Pro+ | Constructors in Python: __init__, __new__ and super() | Medium | Asked in: Accenture, Capgemini, Infosys +2 |
| Pro+ | A child __init__ that skips super() | Easy-Medium | Asked in: Accenture, Capgemini, Infosys +2 |
| Pro+ | Count how many objects of a class were created | Easy-Medium | |
| Pro+ | A subclass that forgets an abstract method | Medium | Asked in: Accenture, Capgemini, Infosys +2 |
| Pro+ | Polymorphism and duck typing in Python | Medium | Asked in: Accenture, Capgemini, Cognizant +3 |
| Pro+ | IS-A versus HAS-A; types of inheritance | Easy-Medium | Asked in: TCS, Wipro |
| Pro+ | Read-only and immutable classes in Python | Medium | Asked in: Accenture, Infosys |
| Pro+ | Where have you used OOP in your Python framework? | Medium | Asked in: Accenture, Capgemini, Salesforce +2 |
| Pro+ | __str__, __repr__, __eq__ and __hash__ | Medium | |
| Pro+ | Can every method be overridden in Python? | Medium | Asked in: Accenture, Capgemini, Infosys +1 |
The first 2 questions of each topic are free. Pro+ opens every question.