Modules, Packages & Imports
Every File Is a Module
Any .py file can be imported. Given helpers.py:
# helpers.py
TAX_RATE = 0.18
def with_tax(amount):
return round(amount * (1 + TAX_RATE), 2)Use it from another file in the same directory:
# main.py
import helpers
print(helpers.with_tax(100)) # 118.0
# or import names directly
from helpers import with_tax, TAX_RATE
print(with_tax(100))Avoid from helpers import * — it dumps unknown names into your namespace and makes code unreviewable.
Aliases
import numpy as np # community-standard aliases
import pandas as pd
from datetime import datetime as dtPackages — Directories of Modules
shop/
├── __init__.py # marks the directory as a package
├── cart.py
├── payments.py
└── utils/
├── __init__.py
└── currency.pyfrom shop.cart import Cart
from shop.utils.currency import to_inr
# inside the package, relative imports:
# shop/payments.py
from .cart import Cart
from .utils.currency import to_inrThe __main__ Guard
When a file is run, its __name__ is "__main__"; when it’s imported, __name__ is the module name. This idiom makes a file both importable and runnable:
# helpers.py
def with_tax(amount): ...
if __name__ == "__main__":
# only runs with: python helpers.py
# never runs on import
print(with_tax(100))Where Python Looks for Imports
Python searches, in order: the script’s directory, then PYTHONPATH, then installed packages (site-packages). The classic gotcha: never name your file after a library — a local random.py shadows the standard library’s random and breaks imports mysteriously.
The Standard Library Is Enormous
Before pip-installing anything, check what ships with Python: json, csv, datetime, pathlib, re, math, random, collections, itertools, functools, sqlite3, http, argparse, logging… “Batteries included” is real.