What's the difference between a module and package in Python?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In Python, both modules and packages are things you can import, which is why they are easy to confuse. The practical difference is that a module is usually one importable file, while a package is a directory-based namespace that groups related modules and sometimes subpackages.
A Module Is the Basic Import Unit
The simplest reusable Python code lives in a module. Most of the time, that means one .py file.
Example file named math_tools.py:
You import it by the file name without the .py suffix:
That file is a module because Python can load it as a named unit. A module can contain:
- functions
- classes
- constants
- top-level executable code
Python's standard library is full of modules such as math, json, and pathlib.
A Package Organizes Multiple Modules
Once a project grows beyond one file, a package becomes useful. A package is a directory that Python treats as an import namespace.
Example layout:
Here:
- '
pricing.pyis a module' - '
inventory.pyis a module' - '
reportsis a subpackage' - '
shopis a package'
That structure enables dotted imports:
The dotted path is the easiest visual signal that you are working with package structure rather than one standalone module.
What __init__.py Does
Traditionally, Python recognized a package by the presence of __init__.py. That file is still useful because it can define package-level behavior or re-export selected names.
Example shop/__init__.py:
Now callers can write:
That can make public package APIs cleaner, though it should be used deliberately. A package should not hide its structure so aggressively that the import surface becomes confusing.
Namespace Packages Add a Modern Twist
There is one complication: modern Python also supports namespace packages, which can exist without __init__.py in some setups. So the beginner rule:
"a package is a directory containing __init__.py"
is helpful, but not complete.
In everyday project code, regular packages with __init__.py are still the clearest model to teach and maintain. Namespace packages become more relevant when large systems split one logical namespace across multiple distributions.
A Package Is Also a Kind of Module
This is the subtle part. In Python's import system, packages are importable objects too. So the distinction is not:
- module means importable
- package means not importable
Instead, the distinction is:
- a module is an importable code unit
- a package is a module-like namespace that can contain other modules
That is why Python documentation sometimes speaks broadly about "modules" even when packages are involved. From the import system's perspective, packages participate in the module system.
Real-World Project Structure
Suppose a small project starts here:
At first, that is fine. Later, the code grows and becomes awkward to manage in one file. Refactoring into a package makes the structure clearer:
Now imports communicate organization:
Packages help when you need:
- cleaner separation of responsibilities
- fewer name collisions
- a stable namespace for related code
They are an organizational tool, not just an import trick.
Do Not Confuse Import Packages with Installed Distributions
Python packaging terminology creates one more source of confusion. People often say "package" to mean something installable with pip. That is related, but not identical.
An installed distribution may provide:
- one package
- several packages
- some top-level modules
So when discussing source code layout, it is safer to ask:
- do you mean an importable package directory
- or a distribution artifact installed by a packaging tool
Those are connected ideas, but they are not the same thing.
Common Pitfalls
One common mistake is calling every Python file a package. A file such as helpers.py is a module, not a package.
Another mistake is assuming packages always require __init__.py. That is usually true in ordinary projects, but namespace packages are a modern exception.
Developers also run into import-shadowing problems. A local module named json.py or random.py can accidentally hide the standard-library module of the same name.
Finally, some projects create deep package hierarchies too early. If a single file is enough, a simple module is often the better design.
Summary
- A module is usually one importable Python file.
- A package is an importable namespace that groups related modules and subpackages.
- '
__init__.pyis still important for ordinary package structure and public package APIs.' - Namespace packages exist, but they are not the best first mental model for beginners.
- Use modules for small units of code and packages when code needs structure under a shared namespace.

