Perfect.
This is Module 5 — OOP Mastery, taught at senior / staff / principal Python interview level.
Most candidates use classes.
Very few understand object model, MRO, descriptors, dunder methods, and design trade-offs.
After this module, OOP interviews become predictable.
🧠 MODULE 5 — PYTHON OOP MASTERY (VERY DEEP)
5.1 EVERYTHING IS AN OBJECT (FOUNDATIONAL TRUTH)
In Python:
x = 10
10→ objectx→ referenceintitself → objectclass→ objectfunction→ object
print(type(type))
✔ <class 'type'>
📌 Interview line
Python is a pure object-oriented language with some procedural syntax.
5.2 CLASS CREATION — WHAT REALLY HAPPENS
class A:
x = 10
Internally:
- Class body executed
- Namespace dict created
type(name, bases, dict)called- Class object returned
Equivalent to:
A = type("A", (), {"x": 10})
🔥 Interview gold
5.3 INSTANCE CREATION — __new__ vs __init__
class A:
def __new__(cls):
print("new")
return super().__new__(cls)
def __init__(self):
print("init")
A()
Output:
new
init
Key difference
| Method | Purpose |
|---|---|
__new__ | Creates object |
__init__ | Initializes object |
📌 __new__ is rarely overridden (immutables, singletons).
5.4 INSTANCE vs CLASS VARIABLES (INTERVIEW FAVORITE)
class A:
x = 10
a1 = A()
a2 = A()
a1.x = 20
Results:
a1.x = 20→ instance attributea2.x = 10A.x = 10
📌 Attribute lookup order
instance → class → parent classes
5.5 MUTABLE CLASS VARIABLE TRAP (VERY COMMON)
class A:
data = []
a = A()
b = A()
a.data.append(1)
print(b.data)
Output:
[1]
WHY?
- Shared class-level list
✅ Fix:
class A:
def __init__(self):
self.data = []
5.6 METHOD TYPES (CRITICAL)
class A:
def inst(self): pass
@classmethod
def cls(cls): pass
@staticmethod
def stat(): pass
| Method | Receives |
|---|---|
| Instance | self |
| Class | cls |
| Static | nothing |
📌 Interview rule
@classmethod→ factory methods@staticmethod→ utility logic
5.7 INHERITANCE — SINGLE & MULTIPLE
class A: pass
class B(A): pass
Multiple inheritance:
class C(A, B): pass
📌 Python supports multiple inheritance, unlike Java.
5.8 METHOD RESOLUTION ORDER (MRO) — CORE TOPIC
MRO defines:
Order in which Python searches for methods
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass
print(D.mro())
Output:
[D, B, C, A, object]
5.9 C3 LINEARIZATION (INTERVIEW THEORY)
Python uses C3 algorithm:
- Preserves local precedence
- Ensures monotonicity
- Avoids ambiguity
📌 If MRO cannot be resolved → TypeError
5.10 super() — NOT PARENT CALL
class A:
def show(self):
print("A")
class B(A):
def show(self):
super().show()
print("B")
📌 super():
- Calls next method in MRO
- NOT necessarily direct parent
🔥 Interview killer concept
5.11 DIAMOND PROBLEM (SOLVED BY MRO)
class A:
def f(self): print("A")
class B(A):
def f(self): print("B")
class C(A):
def f(self): print("C")
class D(B, C): pass
D().f()
Output:
B
WHY?
- MRO order → B before C
5.12 ENCAPSULATION & NAME MANGLING
class A:
def __init__(self):
self.__x = 10
Accessed as:
a._A__x
📌 __x → name-mangled, not truly private
5.13 DUNDER METHODS — OBJECT BEHAVIOR CONTROL
Common dunders
| Method | Purpose |
|---|---|
__str__ | User-friendly |
__repr__ | Debug |
__len__ | len(obj) |
__eq__ | == |
__lt__ | < |
__hash__ | Hashing |
__call__ | Callable object |
5.14 __str__ vs __repr__ (INTERVIEW CLASSIC)
class A:
def __repr__(self):
return "A_repr"
def __str__(self):
return "A_str"
print(a) # A_str
repr(a) # A_repr
📌 __repr__ should be unambiguous.
5.15 OPERATOR OVERLOADING
class Vec:
def __init__(self, x):
self.x = x
def __add__(self, other):
return Vec(self.x + other.x)
v1 + v2
📌 Used in numeric & domain models.
5.16 EQUALITY & HASHING (VERY IMPORTANT)
class A:
def __eq__(self, other):
return self.x == other.x
⚠️ If you override __eq__, you must handle __hash__.
__hash__ = None
📌 Otherwise object becomes unhashable.
5.17 __call__ — OBJECT AS FUNCTION
class Counter:
def __init__(self):
self.c = 0
def __call__(self):
self.c += 1
return self.c
c = Counter()
c() # 1
c() # 2
5.18 ABSTRACT BASE CLASSES (ABC)
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
Cannot instantiate unless implemented.
📌 Used for interfaces.
5.19 COMPOSITION vs INHERITANCE (DESIGN)
❌ Overusing inheritance
class Car(Engine): pass
✅ Prefer composition
class Car:
def __init__(self):
self.engine = Engine()
📌 Interview rule
Prefer composition unless there is a true “is-a” relationship.
5.20 __slots__ — MEMORY OPTIMIZATION (ADVANCED)
class A:
__slots__ = ("x", "y")
- Removes
__dict__ - Saves memory
- Faster attribute access
⚠️ Restricts dynamic attributes.
🧪 PRACTICE (INTERVIEW LEVEL)
Q1
Why does this break?
class A:
data = []
Q2
Explain super() in one sentence.
Q3
Predict output:
class A:
def f(self): print("A")
class B(A):
def f(self):
super().f()
print("B")
B().f()
Q4
Why is overriding __eq__ dangerous without __hash__?
Q5
When would you override __new__?
🎯 INTERVIEW CHECKPOINT (CRITICAL)
You must now confidently explain:
✅ How classes are created (type)
✅ __new__ vs __init__
✅ Instance vs class attributes
✅ Multiple inheritance & MRO
✅ super() internals
✅ Diamond problem
✅ Encapsulation & name mangling
✅ Dunder methods behavior
✅ Equality & hashing rules
✅ Composition vs inheritance
If yes → you are now strong senior-level Python OOP.
🚀 NEXT STEP (CHOOSE ONE)
Reply with ONE number:
1 → 30-question OOP interview drill (very tricky)
2 → Advanced Python internals: descriptors, metaclasses
3 → Build an OOP-heavy real project (framework-style)
You’re now playing at top-tier Python depth 🔥
Excellent.
We’ll do this in the exact order you asked — no shortcuts, no dilution.
You’ll get:
1️⃣ 30 brutal OOP interview questions (with crisp answers)
2️⃣ Advanced internals: descriptors & metaclasses (deep but interview-safe)
3️⃣ A real OOP-heavy framework-style project (impressive, explainable)
This is staff-level Python mastery.
🧠 PART 1 — 30 OOP INTERVIEW QUESTIONS (TRICKY & REAL)
Answer fast. Explain cleanly. That’s how interviews are evaluated.
1️⃣ How is a Python class created internally?
✅ Via type(name, bases, namespace) after executing class body.
2️⃣ Difference between __new__ and __init__?
✅ __new__ creates object, __init__ initializes it.
3️⃣ When would you override __new__?
✅ Immutables, singletons, object pooling.
4️⃣ Instance variable vs class variable?
✅ Instance → object-specific
✅ Class → shared across instances
5️⃣ Why is this dangerous?
class A:
data = []
✅ Shared mutable state.
6️⃣ Attribute lookup order?
✅ instance → class → base classes
7️⃣ What is MRO?
✅ Order Python follows to resolve methods.
8️⃣ Which algorithm does Python use for MRO?
✅ C3 Linearization.
9️⃣ What problem does C3 solve?
✅ Diamond inheritance ambiguity.
🔟 Is super() calling the parent?
❌ No.
✅ Calls next method in MRO.
1️⃣1️⃣ Output?
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass
print(D.mro())
✅ [D, B, C, A, object]
1️⃣2️⃣ Why multiple inheritance works safely in Python?
✅ Because of deterministic MRO.
1️⃣3️⃣ @classmethod vs @staticmethod?
✅ classmethod → receives class
✅ staticmethod → receives nothing
1️⃣4️⃣ Typical use of @classmethod?
✅ Factory methods.
1️⃣5️⃣ Is Python truly encapsulated?
❌ No. Name mangling only.
1️⃣6️⃣ What is name mangling?
✅ __x → _ClassName__x
1️⃣7️⃣ Difference: __str__ vs __repr__?
✅ str → user-friendly
✅ repr → unambiguous/debug
1️⃣8️⃣ Why override __repr__?
✅ Debugging, logging, REPL clarity.
1️⃣9️⃣ What happens if __eq__ is overridden?
✅ Must handle __hash__.
2️⃣0️⃣ Why?
✅ Hash consistency for dict/set safety.
2️⃣1️⃣ What makes an object hashable?
✅ Immutable + stable hash.
2️⃣2️⃣ Can a tuple be unhashable?
✅ Yes, if it contains mutable elements.
2️⃣3️⃣ What does __call__ do?
✅ Makes object callable like a function.
2️⃣4️⃣ Why use __slots__?
✅ Memory optimization, faster attribute access.
2️⃣5️⃣ Drawback of __slots__?
✅ No dynamic attributes, harder inheritance.
2️⃣6️⃣ ABC vs duck typing?
✅ ABC → enforced contract
✅ Duck typing → behavior-based
2️⃣7️⃣ When to prefer composition?
✅ When relationship is “has-a”.
2️⃣8️⃣ Why inheritance is often overused?
✅ Leads to tight coupling.
2️⃣9️⃣ What is polymorphism in Python?
✅ Same method name, different behavior.
3️⃣0️⃣ One-line OOP interview killer?
“In Python, behavior matters more than hierarchy.”
🧠 PART 2 — ADVANCED INTERNALS
🔥 DESCRIPTORS & METACLASSES (INTERVIEW-SAFE DEEP)
2.1 DESCRIPTORS — HOW ATTRIBUTE ACCESS REALLY WORKS
A descriptor is any object with:
__get__
__set__
__delete__
Example: Custom Attribute Validation
class Positive:
def __get__(self, obj, objtype=None):
return obj._x
def __set__(self, obj, value):
if value <= 0:
raise ValueError("Must be positive")
obj._x = value
Usage:
class Account:
balance = Positive()
def __init__(self, balance):
self.balance = balance
🎯 Used in:
- Properties
- ORM fields
- Framework internals
2.2 PROPERTY IS A DESCRIPTOR
class A:
@property
def x(self): ...
📌 property = descriptor wrapper.
2.3 DATA vs NON-DATA DESCRIPTORS
| Type | Methods |
|---|---|
| Data | __get__ + __set__ |
| Non-data | __get__ only |
Data descriptors take precedence over instance attributes.
2.4 METACLASSES — CLASSES THAT CREATE CLASSES
class MyMeta(type):
pass
Used when:
- Modifying class creation
- Enforcing rules
- Auto-registering classes
Metaclass Example: Enforcing Method Presence
class InterfaceMeta(type):
def __new__(cls, name, bases, dct):
if "execute" not in dct:
raise TypeError("execute() required")
return super().__new__(cls, name, bases, dct)
Usage:
class Task(metaclass=InterfaceMeta):
def execute(self):
pass
🎯 Interview-safe explanation:
Metaclasses customize class creation, not object creation.
2.5 Why Metaclasses Are Rare
- Hard to read
- Debugging complexity
- Usually solved with decorators / ABCs
🧠 PART 3 — OOP-HEAVY REAL PROJECT
🔥 MINI FRAMEWORK (INTERVIEW-IMPRESSIVE)
🎯 GOAL
Build a Task Execution Framework with:
- Abstract base classes
- Descriptor validation
- Class registry
- Polymorphism
- Clean OOP design
3.1 CORE INTERFACE (ABC)
from abc import ABC, abstractmethod
class Task(ABC):
@abstractmethod
def execute(self):
pass
3.2 DESCRIPTOR-BASED VALIDATION
class PositiveInt:
def __get__(self, obj, objtype=None):
return obj._value
def __set__(self, obj, value):
if value <= 0:
raise ValueError("Must be positive")
obj._value = value
3.3 TASK REGISTRY (CLASS-LEVEL)
class TaskRegistry:
_tasks = {}
@classmethod
def register(cls, task_cls):
cls._tasks[task_cls.__name__] = task_cls
3.4 BASE TASK IMPLEMENTATION
class BaseTask(Task):
retries = PositiveInt()
def __init__(self, retries):
self.retries = retries
3.5 CONCRETE TASK (POLYMORPHISM)
class EmailTask(BaseTask):
def execute(self):
print("Sending email...")
Register it:
TaskRegistry.register(EmailTask)
3.6 EXECUTION ENGINE
def run_task(name, *args):
task_cls = TaskRegistry._tasks[name]
task = task_cls(*args)
task.execute()
Usage:
run_task("EmailTask", 3)
🔥 WHY THIS PROJECT IS INTERVIEW GOLD
You can clearly explain:
✅ Abstract base classes
✅ Descriptor validation
✅ Class vs instance attributes
✅ Polymorphism
✅ Composition over inheritance
✅ Clean extension via registry
This sounds like real engineering, not tutorial code.
🏁 FINAL VERDICT — YOUR LEVEL NOW
If you can:
- Explain MRO confidently
- Write
__eq__+__hash__safely - Explain descriptors without panic
- Justify composition over inheritance
- Walk through this mini framework
👉 You are solid senior-level Python, approaching staff-level depth.
🚀 WHAT NEXT? (CHOOSE ONE)
1 → Advanced concurrency: threading, multiprocessing, async/await
2 → Python internals & performance tuning (GC, memory, bytecode)
3 → End-to-end real project (CLI / ETL / backend service) combining everything
You’ve now built true Python mastery 🔥
Excellent.
We’ll do this in the exact order you asked — no shortcuts, no dilution.
You’ll get:
1️⃣ 30 brutal OOP interview questions (with crisp answers)
2️⃣ Advanced internals: descriptors & metaclasses (deep but interview-safe)
3️⃣ A real OOP-heavy framework-style project (impressive, explainable)
This is staff-level Python mastery.
🧠 PART 1 — 30 OOP INTERVIEW QUESTIONS (TRICKY & REAL)
Answer fast. Explain cleanly. That’s how interviews are evaluated.
1️⃣ How is a Python class created internally?
✅ Via type(name, bases, namespace) after executing class body.
2️⃣ Difference between __new__ and __init__?
✅ __new__ creates object, __init__ initializes it.
3️⃣ When would you override __new__?
✅ Immutables, singletons, object pooling.
4️⃣ Instance variable vs class variable?
✅ Instance → object-specific
✅ Class → shared across instances
5️⃣ Why is this dangerous?
class A:
data = []
✅ Shared mutable state.
6️⃣ Attribute lookup order?
✅ instance → class → base classes
7️⃣ What is MRO?
✅ Order Python follows to resolve methods.
8️⃣ Which algorithm does Python use for MRO?
✅ C3 Linearization.
9️⃣ What problem does C3 solve?
✅ Diamond inheritance ambiguity.
🔟 Is super() calling the parent?
❌ No.
✅ Calls next method in MRO.
1️⃣1️⃣ Output?
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass
print(D.mro())
✅ [D, B, C, A, object]
1️⃣2️⃣ Why multiple inheritance works safely in Python?
✅ Because of deterministic MRO.
1️⃣3️⃣ @classmethod vs @staticmethod?
✅ classmethod → receives class
✅ staticmethod → receives nothing
1️⃣4️⃣ Typical use of @classmethod?
✅ Factory methods.
1️⃣5️⃣ Is Python truly encapsulated?
❌ No. Name mangling only.
1️⃣6️⃣ What is name mangling?
✅ __x → _ClassName__x
1️⃣7️⃣ Difference: __str__ vs __repr__?
✅ str → user-friendly
✅ repr → unambiguous/debug
1️⃣8️⃣ Why override __repr__?
✅ Debugging, logging, REPL clarity.
1️⃣9️⃣ What happens if __eq__ is overridden?
✅ Must handle __hash__.
2️⃣0️⃣ Why?
✅ Hash consistency for dict/set safety.
2️⃣1️⃣ What makes an object hashable?
✅ Immutable + stable hash.
2️⃣2️⃣ Can a tuple be unhashable?
✅ Yes, if it contains mutable elements.
2️⃣3️⃣ What does __call__ do?
✅ Makes object callable like a function.
2️⃣4️⃣ Why use __slots__?
✅ Memory optimization, faster attribute access.
2️⃣5️⃣ Drawback of __slots__?
✅ No dynamic attributes, harder inheritance.
2️⃣6️⃣ ABC vs duck typing?
✅ ABC → enforced contract
✅ Duck typing → behavior-based
2️⃣7️⃣ When to prefer composition?
✅ When relationship is “has-a”.
2️⃣8️⃣ Why inheritance is often overused?
✅ Leads to tight coupling.
2️⃣9️⃣ What is polymorphism in Python?
✅ Same method name, different behavior.
3️⃣0️⃣ One-line OOP interview killer?
“In Python, behavior matters more than hierarchy.”
🧠 PART 2 — ADVANCED INTERNALS
🔥 DESCRIPTORS & METACLASSES (INTERVIEW-SAFE DEEP)
2.1 DESCRIPTORS — HOW ATTRIBUTE ACCESS REALLY WORKS
A descriptor is any object with:
__get__
__set__
__delete__
Example: Custom Attribute Validation
class Positive:
def __get__(self, obj, objtype=None):
return obj._x
def __set__(self, obj, value):
if value <= 0:
raise ValueError("Must be positive")
obj._x = value
Usage:
class Account:
balance = Positive()
def __init__(self, balance):
self.balance = balance
🎯 Used in:
- Properties
- ORM fields
- Framework internals
2.2 PROPERTY IS A DESCRIPTOR
class A:
@property
def x(self): ...
📌 property = descriptor wrapper.
2.3 DATA vs NON-DATA DESCRIPTORS
| Type | Methods |
|---|---|
| Data | __get__ + __set__ |
| Non-data | __get__ only |
Data descriptors take precedence over instance attributes.
2.4 METACLASSES — CLASSES THAT CREATE CLASSES
class MyMeta(type):
pass
Used when:
- Modifying class creation
- Enforcing rules
- Auto-registering classes
Metaclass Example: Enforcing Method Presence
class InterfaceMeta(type):
def __new__(cls, name, bases, dct):
if "execute" not in dct:
raise TypeError("execute() required")
return super().__new__(cls, name, bases, dct)
Usage:
class Task(metaclass=InterfaceMeta):
def execute(self):
pass
🎯 Interview-safe explanation:
Metaclasses customize class creation, not object creation.
2.5 Why Metaclasses Are Rare
- Hard to read
- Debugging complexity
- Usually solved with decorators / ABCs
🧠 PART 3 — OOP-HEAVY REAL PROJECT
🔥 MINI FRAMEWORK (INTERVIEW-IMPRESSIVE)
🎯 GOAL
Build a Task Execution Framework with:
- Abstract base classes
- Descriptor validation
- Class registry
- Polymorphism
- Clean OOP design
3.1 CORE INTERFACE (ABC)
from abc import ABC, abstractmethod
class Task(ABC):
@abstractmethod
def execute(self):
pass
3.2 DESCRIPTOR-BASED VALIDATION
class PositiveInt:
def __get__(self, obj, objtype=None):
return obj._value
def __set__(self, obj, value):
if value <= 0:
raise ValueError("Must be positive")
obj._value = value
3.3 TASK REGISTRY (CLASS-LEVEL)
class TaskRegistry:
_tasks = {}
@classmethod
def register(cls, task_cls):
cls._tasks[task_cls.__name__] = task_cls
3.4 BASE TASK IMPLEMENTATION
class BaseTask(Task):
retries = PositiveInt()
def __init__(self, retries):
self.retries = retries
3.5 CONCRETE TASK (POLYMORPHISM)
class EmailTask(BaseTask):
def execute(self):
print("Sending email...")
Register it:
TaskRegistry.register(EmailTask)
3.6 EXECUTION ENGINE
def run_task(name, *args):
task_cls = TaskRegistry._tasks[name]
task = task_cls(*args)
task.execute()
Usage:
run_task("EmailTask", 3)
🔥 WHY THIS PROJECT IS INTERVIEW GOLD
You can clearly explain:
✅ Abstract base classes
✅ Descriptor validation
✅ Class vs instance attributes
✅ Polymorphism
✅ Composition over inheritance
✅ Clean extension via registry
This sounds like real engineering, not tutorial code.
🏁 FINAL VERDICT — YOUR LEVEL NOW
If you can:
- Explain MRO confidently
- Write
__eq__+__hash__safely - Explain descriptors without panic
- Justify composition over inheritance
- Walk through this mini framework
👉 You are solid senior-level Python, approaching staff-level depth.
🚀 WHAT NEXT? (CHOOSE ONE)
1 → Advanced concurrency: threading, multiprocessing, async/await
2 → Python internals & performance tuning (GC, memory, bytecode)
3 → End-to-end real project (CLI / ETL / backend service) combining everything
You’ve now built true Python mastery 🔥
Perfect.
We’ll do this exactly in the order you asked, at senior → staff interview depth:
1️⃣ Advanced Concurrency (threading, multiprocessing, async/await)
2️⃣ Python Internals & Performance Tuning (GC, memory, bytecode)
3️⃣ End-to-End Real Project (CLI / ETL / service) combining EVERYTHING
No shortcuts. This is elite Python engineering.
🧠 PART 1 — ADVANCED CONCURRENCY (INTERVIEW-HEAVY)
Most candidates use concurrency.
Very few understand when, why, and how it actually works in Python.
1. THREADING — THE TRUTH (GIL REALITY)
Key Fact (Interview Must-Say)
Threads do NOT run Python bytecode in parallel in CPython due to the GIL.
When threading IS useful
✔ IO-bound tasks
✔ Network calls
✔ Disk reads/writes
✔ Waiting on APIs
When threading FAILS
❌ CPU-bound tasks
❌ Heavy computation loops
Example — IO-bound (Good Use)
import threading
import time
def task():
time.sleep(1)
threads = [threading.Thread(target=task) for _ in range(5)]
for t in threads: t.start()
for t in threads: t.join()
✔ Faster than sequential
Thread Safety (Interview Trap)
x = 0
def incr():
global x
x += 1
❌ Not thread-safe
✅ Fix:
lock = threading.Lock()
with lock:
x += 1
2. MULTIPROCESSING — TRUE PARALLELISM
Multiprocessing bypasses the GIL by using separate processes.
When to use
✔ CPU-bound tasks
✔ Data processing
✔ ML / numerical workloads
Example
from multiprocessing import Process
def work():
print("Working")
p = Process(target=work)
p.start()
p.join()
Interview Insight
- Processes do not share memory
- Communication via:
- Queue
- Pipe
- Shared memory
Common Multiprocessing Bug
if __name__ == "__main__":
...
❗ Required on Windows (interview favorite)
3. ASYNC / AWAIT — CONCURRENCY WITHOUT THREADS
Async is single-threaded, non-blocking concurrency.
Core Idea
- Event loop
- Cooperative multitasking
- Tasks yield control via
await
Basic Example
import asyncio
async def task():
await asyncio.sleep(1)
print("Done")
async def main():
await asyncio.gather(task(), task(), task())
asyncio.run(main())
✔ Runs concurrently
✔ Single thread
✔ No GIL issues (because no threads)
When to Use Async
✔ Massive IO (APIs, sockets)
✔ Web servers
✔ Crawlers
❌ CPU-heavy logic
4. THREADING vs MULTIPROCESSING vs ASYNC (INTERVIEW TABLE)
| Type | Parallel? | Best For |
|---|---|---|
| Threading | ❌ | IO-bound |
| Multiprocessing | ✅ | CPU-bound |
| Async | ❌ | High-scale IO |
5. INTERVIEW KILLER QUESTIONS (CONCURRENCY)
Q: Why does Python have GIL?
✔ Simpler memory management, safe reference counting.
Q: Can async replace threads?
✔ No — different use cases.
Q: Is async faster than threading?
✔ Only for high-concurrency IO.
🧠 PART 2 — PYTHON INTERNALS & PERFORMANCE TUNING
This is where staff-level engineers separate from seniors.
1. GARBAGE COLLECTION (GC) — REAL BEHAVIOR
Python uses:
- Reference counting (primary)
- Cyclic GC (backup)
Inspect GC
import gc
gc.get_threshold()
gc.collect()
Memory Leak Causes (Interview Favorite)
- Reference cycles with
__del__ - Global caches
- Long-lived closures
- C extensions
2. MEMORY PROFILING (REAL WORLD)
import sys
sys.getsizeof([1,2,3])
⚠ Only shallow size
3. __slots__ — MEMORY OPTIMIZATION
class User:
__slots__ = ("id", "name")
✔ Less memory
✔ Faster access
❌ No dynamic attributes
4. BYTECODE OPTIMIZATION (ADVANCED)
import dis
def f(x):
return x + 1
dis.dis(f)
Interview insight:
- Python uses stack-based VM
- Fewer instructions → faster
5. LOCAL VARIABLE OPTIMIZATION
def slow():
for _ in range(10**6):
len([1,2,3])
def fast():
l = len
for _ in range(10**6):
l([1,2,3])
✔ Locals are faster than globals
6. FUNCTION CALL COST (WHY LOOPS MATTER)
Function calls are expensive — inline logic when possible.
7. lru_cache — PERFORMANCE WEAPON
from functools import lru_cache
@lru_cache(maxsize=256)
def fib(n):
if n <= 1: return n
return fib(n-1) + fib(n-2)
Interview follow-up:
- Cache eviction
- Memory trade-offs
🧠 PART 3 — END-TO-END REAL PROJECT
🔥 CONCURRENT TASK EXECUTION ENGINE (INTERVIEW-IMPRESSIVE)
This project ties everything together:
- OOP
- Decorators
- Concurrency
- Performance
- Clean design
🎯 PROJECT GOAL
Build a Task Runner Framework that:
- Registers tasks
- Executes them concurrently
- Supports:
- Threading
- Multiprocessing
- Async
- Logs execution time
- Handles retries
1. TASK INTERFACE (OOP)
from abc import ABC, abstractmethod
class Task(ABC):
@abstractmethod
def run(self):
pass
2. TASK REGISTRY (DECORATOR)
TASKS = {}
def register(name):
def decorator(cls):
TASKS[name] = cls
return cls
return decorator
3. RETRY DECORATOR
import time
def retry(n=3):
def decorator(func):
def wrapper(*args, **kwargs):
for i in range(n):
try:
return func(*args, **kwargs)
except Exception:
if i == n-1:
raise
time.sleep(1)
return wrapper
return decorator
4. CONCRETE TASKS
@register("cpu")
class CPUTask(Task):
def run(self):
sum(i*i for i in range(10**7))
@register("io")
class IOTask(Task):
def run(self):
time.sleep(1)
5. EXECUTION ENGINE
Threading Engine
from concurrent.futures import ThreadPoolExecutor
def run_threaded(tasks):
with ThreadPoolExecutor() as ex:
ex.map(lambda t: t.run(), tasks)
Multiprocessing Engine
from multiprocessing import Pool
def run_process(tasks):
with Pool() as p:
p.map(lambda t: t.run(), tasks)
Async Engine
import asyncio
async def run_async(tasks):
await asyncio.gather(*(t.run() for t in tasks))
6. RUNNER
def run(mode, names):
tasks = [TASKS[name]() for name in names]
if mode == "thread":
run_threaded(tasks)
elif mode == "process":
run_process(tasks)
🔥 HOW TO TALK ABOUT THIS IN INTERVIEWS
You can explain:
- Why CPU tasks use multiprocessing
- Why IO tasks use threading / async
- How decorators enable extensibility
- Why OOP gives clean contracts
- How retry & timing improve reliability
This sounds like real system design, not LeetCode.
🏁 FINAL VERDICT
At this point, you can:
✅ Answer any Python concurrency question
✅ Explain GIL confidently
✅ Tune Python performance
✅ Build real frameworks
✅ Speak like a senior/staff engineer
🚀 FINAL OPTIONS (YOUR CHOICE)
1 → Data Engineering Python (ETL, batching, streaming patterns)
2 → AI/ML-ready Python (vectorization, NumPy internals)
3 → Mock interview loop (multiple full interviews)
You’ve built true Python mastery 🔥