Python modules and packages: import, __init__.py, relative imports and __name__
Advertisement
A single Python file is fine for a small script. As a project grows, you need to split it into files and group those files into folders. Python has two words for this: a module is one .py file, and a package is a folder of modules. This post explains how to create both, the different ways to import from them, what __init__.py does, how relative imports and __name__ work, and how to fix the import errors everyone meets. The example project below was actually built and run.
Modules
Any Python file can be imported by its name without the .py. If helpers.py contains def greet(): ..., another file in the same folder can do:
import helpers
helpers.greet()
from helpers import greet # import one name
import helpers as h # give the module a short alias
from helpers import * # import everything public (avoid in real code)
Prefer explicit imports. from x import * hides where names come from and can overwrite your own.
The first time a module is imported, Python runs it from top to bottom and stores the result in sys.modules. Later imports reuse that stored module, so top-level code runs only once per program.
The standard library is a collection of ready-made modules (math, os, json, re, datetime), and pip installs third-party ones.
Packages
Make a folder, put modules in it, and add a file named __init__.py:
shop/
__init__.py
tools/
__init__.py
price.py
text.py
models/
__init__.py
item.py
main.py
Here are the files (kept short on purpose):
# shop/__init__.py
print("shop package loaded")
VERSION = "1.0"
from .tools.price import with_tax
__all__ = ["with_tax", "VERSION"]
# shop/tools/price.py
TAX = 0.18
def with_tax(amount):
return round(amount * (1 + TAX), 2)
# shop/tools/text.py
from .price import TAX
from ..models.item import Item
def label(item):
return f"{item.name}: {item.price} (tax {TAX})"
# shop/models/item.py
class Item:
def __init__(self, name, price):
self.name, self.price = name, price
def __repr__(self): return f"Item({self.name!r}, {self.price})"
if __name__ == "__main__":
print("run as script:", __name__)
else:
print("imported as:", __name__)
(shop/tools/__init__.py and shop/models/__init__.py are empty files.) And a script that uses the package:
# main.py
import shop
print(shop.VERSION, shop.with_tax(100))
from shop.models.item import Item
from shop.tools import text
print(text.label(Item("Tea", 50)))
import shop.tools.price as p
print(p.__name__, shop.__name__, shop.__package__, text.__package__)
Running python3 main.py from the project folder printed:
shop package loaded
1.0 118.0
imported as: shop.models.item
Tea: 50 (tax 0.18)
shop.tools.price shop shop shop.tools
Notice the order: the message from shop/__init__.py appears first, as soon as the package is imported, and the line from item.py appears when main.py imports it. Each module's own __name__ is its dotted path (shop.tools.price).
What __init__.py does
- It marks a folder as a package (modern Python can also import folders without it, called namespace packages, but an explicit
__init__.pyis clearer and expected by most tools). - Its code runs once, when the package is first imported. Use it to set up the package, define a
VERSION, or import the most useful names so users can writeshop.with_tax(...)instead ofshop.tools.price.with_tax(...). __all__lists the names thatfrom shop import *should export.
Keep __init__.py light. Heavy work there slows down every import of the package.
Absolute and relative imports
An absolute import starts at the top of the package: from shop.tools.price import with_tax. It works the same from anywhere and is the recommended default.
A relative import starts from the current module's position: one dot is "this package", two dots is "the parent package".
Written inside shop/tools/text.py |
Means |
|---|---|
from .price import TAX |
the module price in the same package |
from ..models.item import Item |
models.item in the parent package shop |
from . import price |
the price module from this package |
Relative imports only work inside a package and when the file is imported as part of it. They make it easy to rename or move the whole package.
__name__ and running a file directly
Every module has a __name__. When you run a file directly, it is "__main__"; when it is imported, it is the module's name. That lets a file be both a library and a program:
if __name__ == "__main__":
main()
The block runs only when the file is run, not when it is imported. In our example, running the module in two ways gave different results:
$ python3 -m shop.models.item # run as part of the package
shop package loaded
run as script: __main__
$ python3 shop/models/item.py # run as a plain script
run as script: __main__
The -m form imports shop first (so its message appears) and then runs the module. Running a file inside a package as a plain script breaks relative imports, because Python does not know it belongs to a package. If a file with from .price import TAX is run by path, it fails with ImportError: attempted relative import with no known parent package. Use python -m package.module for such files.
Where Python looks: sys.path
When you write import something, Python searches in order: the built-in modules, then each folder in sys.path, which holds the script's folder (or the current folder in an interactive session), the folders in the PYTHONPATH variable, the standard library and installed packages (site-packages).
import sys
print(type(sys.path)) # <class 'list'>
You can inspect sys.modules to see what has been imported ("shop" in sys.modules was True after the import), and module.__file__ to see where a module came from. To import by name at run time, use importlib.import_module("shop.models.item").
Do not edit sys.path as a normal practice. Better ways: run your program from the project root, install the project in a virtual environment (pip install -e .), or use python -m.
Common errors and fixes
| Error | Usual cause | Fix |
|---|---|---|
ModuleNotFoundError: No module named 'nothere' |
Misspelled name, not installed, or not on sys.path |
Check spelling; pip install; run from the project root |
ImportError: cannot import name 'x' |
The module exists but has no such name | Check the name and for circular imports |
ImportError: attempted relative import with no known parent package |
A relative import in a file run as a script | Run with python -m package.module |
| Importing your own file shadows a library | You named a file random.py or json.py |
Rename it |
| Circular import | Module A imports B and B imports A at top level | Move shared code to a third module, or import inside a function |
The shadowing problem is a favourite: a file called random.py in your folder will be imported instead of the standard library's, and strange errors follow.
Layout tips
- Name modules in short lower-case words (
price.py), packages likewise. - One clear responsibility per module.
- Put tests in a separate
tests/folder. - Keep the package folder directly under the project root so
python -mand imports work. - Document the public names, and keep internal helpers behind a leading underscore.
Practice
Create a package called utils with modules text.py (a function slug(title)) and numbers.py (average(values)), expose both from __init__.py, and call them from a main.py. Then add a if __name__ == "__main__": demo to numbers.py and run it both ways. Break the layout on purpose (rename __init__.py, run a file with a relative import by path) and read the errors.
Continue
Imports pair naturally with the other building blocks: language fundamentals, regular expressions (the re module) and logging (the logging package, which has its own submodules). Practise with the Python video course and check yourself with the interview questions.