runtime
108 / 250
lesson 108 Modules & Packages · intermediate

Packages: folders of modules

A folder with an __init__.py is a package. Dotted imports reach the modules inside it, modules in the package import each other with relative imports, and __init__.py decides what the package itself offers.

You'll be able to
  • Import from a package with import shop.tax and from shop.pricing import price_with_tax
  • Use relative imports (from .tax import rate_for) between modules of the same package
  • Re-export names in __init__.py, and recognise the error from a relative import outside a package
The idea

Ten modules in one folder get hard to find. A package groups related modules in a folder: shop/pricing.py, shop/tax.py, plus shop/__init__.py, which marks the folder as a package and runs when the package is first imported.

From outside, dotted names reach inside: import shop.tax (then shop.tax.rate_for(...)) or from shop.pricing import price_with_tax. Inside the package, modules import their neighbours with relative imports: from .tax import rate_for means "the tax module in my own package", so the package keeps working if the folder is renamed or moved.

Run each example to see what it prints. Running examples doesn't count toward progress.

example-1.py · A shop package with two modules
from pathlib import Path
import importlib

Path("shop").mkdir(exist_ok=True)
Path("shop/__init__.py").write_text('"""Runtime Market shop helpers."""\n', encoding="utf-8")
Path("shop/tax.py").write_text('''from decimal import Decimal

RATES = {"NY": Decimal("0.08875"), "FL": Decimal("0.07"), "OR": Decimal("0")}

def rate_for(state):
    return RATES.get(state, Decimal("0.05"))
''', encoding="utf-8")
Path("shop/pricing.py").write_text('''from decimal import Decimal, ROUND_HALF_UP
from .tax import rate_for

def price_with_tax(price_text, state):
    total = Decimal(price_text) * (1 + rate_for(state))
    return total.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
''', encoding="utf-8")
importlib.invalidate_caches()

from shop.pricing import price_with_tax
import shop.tax

print(price_with_tax("47.99", "NY"), price_with_tax("47.99", "OR"))
print(shop.tax.rate_for("FL"))
example-2.py · A relative import in the program you run
from .tax import rate_for

__init__.py can also choose what the package offers at the top level. With from .pricing import price_with_tax inside it, users can write from shop import price_with_tax without knowing which module the function lives in, and you can reorganise the modules later without breaking them.

example-3.py · Re-exporting from __init__.py
from pathlib import Path
import importlib

Path("catalog").mkdir(exist_ok=True)
Path("catalog/__init__.py").write_text('from .lookup import find_product\n', encoding="utf-8")
Path("catalog/lookup.py").write_text('''PRODUCTS = {"HOM-52782": "Deluxe Pillow", "GRO-63674": "Pro Honey"}

def find_product(sku):
    return PRODUCTS.get(sku, "unknown product")
''', encoding="utf-8")
importlib.invalidate_caches()

from catalog import find_product
import catalog

print(find_product("HOM-52782"), "|", catalog.find_product("XXX-00000"))
print(catalog.lookup.find_product("GRO-63674"))

When to use it: once a project has more than a handful of modules, group them by responsibility (shop.pricing, shop.tax, shop.export). Mistakes to avoid: relative imports in the script you run, forgetting __init__.py (it isn't strictly required in modern Python, but without it the folder is a looser "namespace package" and many tools expect it), and circular imports, where two modules import each other at the top.

Review
  • A folder with __init__.py is a package; __init__.py runs on the package's first import.
  • From outside: import shop.tax or from shop.pricing import name. Inside: from .tax import name.
  • Relative imports only work inside a package, never in the program you run.
  • Next: one file that is both a module and a program.
Practise this

Loading your progress…

To master this lesson, solve both challenges without hints or the answer, and pass the concept check.

Packages: folders of modules — Modules & Packages · Runtime