Python
module
package
programming
Python development

What's the difference between a module and package in Python?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

A Python module is a single .py file containing definitions and statements. A Python package is a directory containing multiple modules and an __init__.py file (or configured as a namespace package). Modules organize code within a file, packages organize modules into a directory hierarchy. You import a module by its filename and import a package by its directory name. Understanding the distinction is essential for structuring Python projects beyond simple scripts.

Modules

A module is any single .py file.

python
1# math_utils.py — this is a module
2def add(a, b):
3    return a + b
4
5def multiply(a, b):
6    return a * b
7
8PI = 3.14159
python
1# Using the module
2import math_utils
3
4print(math_utils.add(3, 4))       # 7
5print(math_utils.PI)               # 3.14159
6
7# Import specific names
8from math_utils import add, PI
9print(add(3, 4))                   # 7
10
11# Import with alias
12import math_utils as mu
13print(mu.multiply(3, 4))           # 12

Every .py file you create is automatically a module. Python's standard library is also a collection of modules (os, sys, json, math, etc.).

Packages

A package is a directory containing an __init__.py file and one or more modules.

 
1myproject/
2├── main.py
3└── utils/               # This is a package
4    ├── __init__.py       # Makes utils/ a package
5    ├── math_utils.py     # Module inside the package
6    ├── string_utils.py   # Another module
7    └── io/               # Sub-package
8        ├── __init__.py
9        └── file_utils.py
python
1# main.py — importing from the package
2from utils.math_utils import add
3from utils.string_utils import capitalize
4from utils.io.file_utils import read_file
5
6# Or import the package itself
7import utils.math_utils
8result = utils.math_utils.add(3, 4)

The __init__.py File

__init__.py runs when the package is imported. It can be empty or can define the package's public API.

python
1# utils/__init__.py — define what "from utils import *" exports
2from .math_utils import add, multiply
3from .string_utils import capitalize
4
5__all__ = ['add', 'multiply', 'capitalize']
python
# Now you can import directly from the package
from utils import add, capitalize
# Instead of: from utils.math_utils import add

Namespace Packages (Python 3.3+)

Python 3.3+ supports packages without __init__.py — these are namespace packages. They allow a package to span multiple directories.

 
1# Two separate directories, same package name
2site-packages/
3├── mypkg/          # No __init__.py
4│   └── module_a.py
5└── other-lib/
6    └── mypkg/      # No __init__.py
7        └── module_b.py
8
9# Both are accessible under "mypkg"
10import mypkg.module_a
11import mypkg.module_b

Regular packages (with __init__.py) are preferred for most projects. Namespace packages are mainly used by large frameworks that split across multiple distributions.

Key Differences

FeatureModulePackage
What it isA single .py fileA directory of modules
Requires __init__.pyNoYes (regular) or No (namespace)
ContainsFunctions, classes, variablesModules and sub-packages
Import syntaximport moduleimport package.module
__file__ attributePath to .py filePath to __init__.py
__path__ attributeNot presentList of directory paths
python
1import os
2import json
3import utils
4
5print(type(os))       # <class 'module'>
6print(type(json))     # <class 'module'>
7print(type(utils))    # <class 'module'> — packages are also modules!
8
9# Distinguish by __path__
10print(hasattr(os, '__path__'))    # True — os is a package
11print(hasattr(json, '__path__'))  # False — json is a module (C extension)

Relative Imports Within Packages

python
1# utils/string_utils.py — import from sibling module
2from .math_utils import add          # Relative import (same package)
3from ..other_package import helper   # Parent package relative import
4
5# Relative imports only work inside packages
6# They do NOT work in top-level scripts

Common Pitfalls

  • Missing __init__.py: Without __init__.py, Python 2 does not recognize the directory as a package. Python 3 treats it as a namespace package, which behaves differently (no package-level code execution). Always include __init__.py for regular packages.
  • Circular imports: If module_a imports from module_b and module_b imports from module_a, Python raises ImportError or returns partially initialized modules. Break cycles by moving shared code to a third module or using lazy imports inside functions.
  • Shadowing standard library modules: Naming your file json.py or os.py shadows the standard library module. import json will import your file instead of the built-in. Never name your modules the same as standard library modules.
  • Running a module inside a package as a script: Running python utils/math_utils.py directly makes Python treat it as a top-level script, breaking relative imports. Use python -m utils.math_utils to run it as a module within the package.
  • Confusing import package with importing all modules: import utils only runs utils/__init__.py — it does not automatically import all modules inside the package. You must explicitly import each module (from utils import math_utils) or list them in __init__.py.

Summary

  • A module is a single .py file; a package is a directory containing modules and __init__.py
  • Packages organize related modules into a hierarchy (e.g., utils.math_utils, utils.io.file_utils)
  • __init__.py defines the package's public API and runs on import
  • Use relative imports (.module) within packages for internal references
  • Never name your modules the same as standard library modules to avoid shadowing

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.