import math
print(math.pi) # Must use module prefix
# Import specific items
from math import sqrt, pi
print(sqrt(16)) # Used directly, no prefix
# Import everything (⚠️ BAD PRACTICE — pollutes namespace)
# from math import *from datetime import datetime as dt
from collections import defaultdict as ddPython finds modules in this order:
print(sys.path)
# Add custom directory temporarily
sys.path.append('/my/custom/modules')
def main():
print('Running as script')
# This runs ONLY when executed directly: python my_module.py
# It does NOT run when imported: import my_module
if __name__ == '__main__':
main()Why? Prevents test code/execution code from running when the file is imported as a module elsewhere.
import my_module # Loads and executes
import my_module # Uses cached version, does NOT re-execute
# Force reload (useful in Jupyter notebooks)
import importlib
importlib.reload(my_module)
# Check what's loaded
print(sys.modules.keys())# b.py imports a.py
# ❌ This causes an error!
# Solutions:
# 1. Restructure code to remove circular dependency
# 2. Import inside the function, not at the top of the file
# def func():
# from module_b import something # Lazy import# from . import sibling_module # Relative (same directory)
# from .subpkg import module # Relative (sub-directory)
# from mypackage.subpkg import mod # Absolute (from project root)Create a mock module structure using strings to demonstrate the concept. Write a string representing `calc.py` containing `add(a, b)` and a `if __name__ == '__main__':` block. Write another string representing `main.py` that imports from calc. Print both. Then, write a function `get_module_info(module_name)` that tries to import a given module name dynamically using `importlib.import_module` and returns its file path or 'Not found'.