Excellent.
DAY 17 removes all mystery around Python imports — one of the most common sources of production bugs, interview questions, and circular nightmares.
After today, you’ll know exactly how Python finds, loads, caches, and executes code.
🧠 DAY 17 — Modules, Imports & sys.path
(How Python Finds, Loads & Executes Code)
🔑 CORE IDEA OF DAY 17
importis not just “including a file”.
It is a controlled, cached execution process governed bysys.path.
1️⃣ What Is a Module vs Package (Precise)
Module
- A single
.pyfile - Has its own namespace
math.py
Package
- A directory of modules
- Contains
__init__.py(explicit or implicit)
mypkg/
├── __init__.py
├── a.py
└── b.py
Both are objects at runtime.
2️⃣ What REALLY Happens When You import x
Let’s break this down step by step.
import mymodule
Python does:
- Check module cache (
sys.modules) - If found → reuse it (no re-execution)
- If not found:
- Search locations in
sys.path
- Search locations in
- Load module
- Execute module top to bottom
- Store module object in
sys.modules - Bind name
mymodulein caller’s namespace
⚠️ Import executes code exactly once per process
3️⃣ The Import Search Path (sys.path)




Order of search:
- Current script directory
- Entries in
PYTHONPATH - Standard library directories
- Site-packages
Inspect:
import sys
sys.path
🧠 Wrong imports = wrong path order
4️⃣ sys.modules — The Import Cache (CRITICAL)
import math
import math
mathloaded once- Second import reuses cached object
import sys
print("math" in sys.modules)
This explains:
- Why imports are fast after first time
- Why circular imports behave strangely
5️⃣ Import Styles (And What They REALLY Do)
import module
import math
math.sqrt(4)
- Binds name
math - Namespace is explicit
- Safest form
from module import name
from math import sqrt
sqrt(4)
- Binds
sqrtdirectly - No module prefix
- Faster lookup
- Higher collision risk
from module import * ❌
from math import *
Problems:
- Pollutes namespace
- Unclear origins
- Breaks static analysis
🚨 Avoid in real code
6️⃣ Packages & __init__.py (Often Misunderstood)
__init__.py:
- Executes when package is imported
- Can expose API
- Can import submodules
# mypkg/__init__.py
from .a import func
Now:
import mypkg
mypkg.func()
🧠 __init__.py defines the public surface of a package.
7️⃣ Absolute vs Relative Imports
Absolute (Recommended)
from mypkg.sub import mod
Relative (Inside packages only)
from . import mod
from ..utils import helper
Rules:
- Relative imports only work inside packages
- Never use relative imports in scripts
8️⃣ Circular Imports (🔥🔥🔥 Interview Favorite)
Example
# a.py
import b
# b.py
import a
What happens:
astarts importingbimportsaais only partially initialized- Attribute access fails
🚨 This causes AttributeError, not ImportError.
9️⃣ How to Break Circular Imports (REAL STRATEGIES)
✅ Strategy 1: Move import inside function
def f():
import b
✅ Strategy 2: Refactor shared logic
- Create
common.py - Both modules import it
✅ Strategy 3: Import modules, not names
import module
module.func()
🔟 __name__ == "__main__" (DEMYSTIFIED)
Every module has __name__.
- If run directly →
"__main__" - If imported → module name
if __name__ == "__main__":
main()
Purpose:
- Allow file to be both script and module
- Prevent accidental execution on import
This is not optional boilerplate — it’s a design pattern.
11️⃣ Import Time Side Effects (DANGEROUS)
# bad_module.py
print("hello")
x = expensive_call()
This runs on import, not on use.
Best practice:
- Keep imports lightweight
- Put heavy logic inside functions
12️⃣ Reloading Modules (Advanced)
import importlib
importlib.reload(module)
Use cases:
- REPL
- Debugging
- Not recommended in production
Reloading does NOT:
- Reset references held elsewhere
- Fully clean state
🔥 INTERVIEW TRAPS (DAY 17)
Q1
import math
import math
How many times is math executed?
✔ Once
Q2
Why circular imports cause partial objects?
✔ Module added to sys.modules before execution completes
Q3
Difference between import x and from x import y?
✔ Namespace binding
✔ Lookup path
✔ Collision risk
Q4
Why is if __name__ == "__main__" important?
✔ Prevent side effects
✔ Enable reuse
✔ Script/module duality
🧠 DAY 17 MENTAL CHECKLIST
When debugging imports:
- Is module already in
sys.modules? - Is execution happening at import time?
- Is path order correct?
- Is there a circular dependency?
- Is
__init__.pydoing too much?
📝 DAY 17 ASSIGNMENT (MANDATORY)
1️⃣ Predict behavior (NO RUNNING):
# a.py
print("A")
import b
# b.py
print("B")
import a
What prints? Why?
2️⃣ Explain clearly:
- Why imports are cached
- Why circular imports fail silently at first
3️⃣ Design question:
How would you structure a large project to avoid circular imports?
🔜 DAY 18 PREVIEW
DAY 18 — OOP Fundamentals (Python’s Object-Oriented Model)
You’ll learn:
- Classes vs instances
- Attribute lookup order
__init__is not constructor- How Python OOP differs from Java/C++
When ready, say 👉 “START DAY 18”