1. Class & instance attributes
- Class attribute — defined in the class body; shared by all instances.
- Instance attribute — set on
self; belongs to one object. - Shadowing: reading
self.namefinds the instance attr first; settingself.namenever mutates the class attr (creates a new instance attr).
class Car:
wheels = 4 # class attr, shared
c1, c2 = Car(), Car()
print(c1.wheels, c2.wheels) # 4 4
c1.wheels = 6 # creates new instance attr on c1 only
print(c1.wheels, c2.wheels, Car.wheels) # 6 4 4
2. Constructors & self
__init__is the initializer (not the constructor — that’s__new__).__new__creates the instance (used for singletons, immutable types);__init__sets it up.selfis the conventional name for the instance; methods receive it explicitly.- Classmethods (
@classmethod, receivecls) and staticmethods (@staticmethod, no automatic first arg) differ.
3. Inheritance & MRO
- Single inheritance + mixins are idiomatic; multiple inheritance forces an MRO.
- MRO (Method Resolution Order) in Python 3 = C3 linearization; inspect with
Class.__mro__. - A method lookup walks MRO left-to-right, depth-first, then superclasses — the first match wins.
super()is not “the parent class” — it’s a proxy that follows the MRO afterself’s class. It makes cooperative diamond inheritance work.
class A: ...
class B(A): ...
class C(A): ...
class D(B, C): ...
print(D.__mro__) # D → B → C → A → object
- Diamond: with cooperative
super(), each ancestor’s method runs exactly once.
4. Abstract classes
- Via
abc.ABC+@abstractmethod. - An abstract class cannot be instantiated; subclasses must implement abstract methods.
- Interface-like contracts are expressed with ABCs +
@abstractmethod.
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self): ...
5. Properties & encapsulation
- Python has no
privatekeyword — name mangling_nameis convention. __name(double underscore) inside a class triggers name mangling →_ClassName__name, discouraging accidental access (not real security).@propertyturns a method into an attribute-like accessor; getter/setter/deleter.
class Temp:
def __init__(self): self._c = 0
@property
def celsius(self): return self._c
@celsius.setter
def celsius(self, v): self._c = v
6. Magic methods cheat-sheet
| Category | Methods |
|---|---|
| Init | __new__, __init__, __del__ |
| Represent | __repr__ (dev), __str__ (user) |
| Equality | __eq__, __ne__, __lt__, __le__, __gt__, __ge__, __hash__ |
| Containers | __len__, __getitem__, __setitem__, __contains__, __iter__ |
| Context | __enter__, __exit__ (context manager) |
| Callable | __call__ |
| Arithmetic | __add__, __sub__, __mul__, … reflected __radd__ |
__eq__and__hash__: defining__eq__sets__hash__toNone→ the object becomes unhashable unless you re-implement__hash__. Classic interview point.__str__vs__repr__:print()uses__str__; interpreter/repr()uses__repr__; fall back to each other.
7. Interview checkpoint
- Class vs instance attribute shadowing.
- MRO + diamond — why C3 and
super()matter. __eq__/__hash__coupling (objects as dict keys).@property, dataclasses (@dataclassauto-generates__init__,__repr__,__eq__).isvs==in OOP (identity vs semantic equality).
Premium Content
Unlock Part 3: OOP & Magic Methods and all premium lessons with a subscription.
All premium lessons
Ad-free experience
Priority support
From ₹199.99/year — See plans