Python Modules and Packages: Organize Imports

Updated on: August 20, 2026
Reading time: 5 minutes
Caixas empilhadas

As a Python project grows, keeping every function and class in one file becomes difficult. Python modules and packages solve that problem by dividing code into focused, reusable parts.

A module is usually one .py file. A package is a directory that groups related modules. Together, they help you create clearer projects, reuse code, write tests, and collaborate without turning one script into thousands of lines.

What is a Python module?

Any Python file can act as a module. Suppose a project contains a file named calculator.py:

# calculator.py

def add(a, b):
    return a + b

def subtract(a, b):
    return a - b

PI = 3.14159

Another file can import and use it:

# main.py
import calculator

print(calculator.add(10, 5))
print(calculator.PI)

The module name is the filename without .py. The official Python modules tutorial explains how Python loads files and creates module namespaces.

Different import styles

The regular import form keeps the module name visible:

import calculator
result = calculator.add(4, 8)

You can import specific names:

from calculator import add, subtract
print(add(4, 8))

Aliases are useful for long or conventional names:

import calculator as calc
print(calc.subtract(20, 3))

Avoid from module import *. It hides where names come from and can silently overwrite variables. Clear imports support the naming and organization rules discussed in the PEP 8 guide.

How Python finds modules

When Python sees an import, it checks several locations, including the current project, the standard library, installed packages, and directories listed in sys.path.

import sys

for folder in sys.path:
    print(folder)

A common mistake is naming your own file after a standard or third-party module. A file called random.py, json.py, or requests.py can shadow the real library and cause confusing import errors. The guide to fixing ModuleNotFoundError covers environment and path problems in detail.

What is a Python package?

A package is a directory containing modules that belong together. A small store application might use this structure:

store_app/
├── main.py
└── store/
    ├── __init__.py
    ├── products.py
    ├── orders.py
    └── reports.py

The store directory is the package. Each Python file inside it is a submodule.

# store/products.py

def calculate_total(price, quantity):
    return price * quantity
# main.py
from store.products import calculate_total

print(calculate_total(19.90, 3))

What does __init__.py do?

The __init__.py file marks a regular package and can define the public interface that users import. It may be empty, but it can also re-export selected names:

# store/__init__.py
from .products import calculate_total

__all__ = ["calculate_total"]

Now the application can use:

from store import calculate_total

Keep __init__.py lightweight. Running database connections, network requests, or expensive calculations during import makes applications slow and unpredictable.

Absolute and relative imports

An absolute import begins at the top-level package:

from store.products import calculate_total

A relative import uses dots to refer to nearby modules:

# store/reports.py
from .products import calculate_total

Absolute imports are often easier to understand in application code. Relative imports can be convenient inside a cohesive package. Consistency is more important than mixing styles without a reason.

Using __name__ and running a module

Every module has a __name__ variable. When a file runs directly, its value is "__main__". When imported, it contains the module name.

# temperature.py

def celsius_to_fahrenheit(value):
    return value * 9 / 5 + 32

if __name__ == "__main__":
    print(celsius_to_fahrenheit(25))

This guard prevents demonstration or command-line code from running merely because the module was imported.

Packages can also be executed with python -m package.module. This approach preserves the import context and often avoids path errors.

Designing a useful project structure

A beginner-friendly application might look like this:

expense_tracker/
├── README.md
├── pyproject.toml
├── src/
│   └── expense_tracker/
│       ├── __init__.py
│       ├── models.py
│       ├── storage.py
│       └── cli.py
└── tests/
    ├── test_models.py
    └── test_storage.py

The src layout helps prevent accidental imports from the project folder. Tests live separately but import the installed package. The article about unit testing in Python shows how this separation improves test organization.

Modules, packages, libraries, and distributions

These terms are related but not identical:

  • Module: one importable Python file.
  • Package: an importable directory of modules.
  • Library: a general term for reusable code.
  • Distribution: the installable project published to a package index.

A distribution can contain one or more packages. The guide to Python libraries explains how reusable code is installed and used, while the tutorial on creating an installable package covers packaging metadata and builds.

A practical example

Consider a package that formats customer data:

customer_tools/
├── __init__.py
├── names.py
└── validation.py
# customer_tools/names.py

def normalize_name(name):
    return " ".join(part.capitalize() for part in name.split())
# customer_tools/validation.py

def is_valid_email(email):
    return "@" in email and "." in email.rsplit("@", 1)[-1]
# customer_tools/__init__.py
from .names import normalize_name
from .validation import is_valid_email
from customer_tools import normalize_name, is_valid_email

name = normalize_name("  aLEX johnSON ")
email = "alex@example.com"

print(name)
print(is_valid_email(email))

This organization gives each module one responsibility and creates a simple public interface.

Avoiding circular imports

A circular import happens when module A imports module B while module B imports module A. Python may encounter a partially initialized module and raise an error.

Common solutions include moving shared definitions into a third module, importing a dependency inside a function only when necessary, or redesigning responsibilities so modules do not depend on each other in both directions.

package/
├── common.py
├── users.py
└── orders.py

Both users.py and orders.py can import shared types from common.py without importing each other.

Common mistakes

Running an internal file directly

Executing python package/module.py can break relative imports. Run it from the project root with python -m package.module.

Depending on the current working directory

Build file paths from __file__ or use pathlib rather than assuming the terminal always starts in one folder.

Putting unrelated code in one package

A package should represent a coherent feature or domain. Split independent concerns into separate packages.

Creating too many tiny modules

Organization should reduce complexity, not create a maze. A module with one trivial function is not automatically better than a clear, focused file containing several related functions.

Best practices

  • Use lowercase module and package names.
  • Give each module a clear responsibility.
  • Keep imports at the top unless a local import solves a specific problem.
  • Expose a small, intentional public API.
  • Avoid side effects during import.
  • Use virtual environments to isolate dependencies. The venv tutorial explains the workflow.
  • Add tests before reorganizing a mature project.

Conclusion

Python modules and packages turn a growing script into a maintainable application. Begin by moving related functions into modules, group those modules into packages, use explicit imports, and keep dependencies flowing in one clear direction.

For deeper reference, review the official Python import system documentation. A small project organized into two or three modules is the best place to practice before designing a larger installable package.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    A solitary tree with sunlight filtering through the leaves on a grassy hill under a blue sky.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    ElementTree: Read and Modify XML in Python

    Learn Python ElementTree to read, search, modify, and generate XML with namespaces, incremental parsing, limits, and security.

    Ler mais

    Tempo de leitura: 5 minutos
    22/08/2026
    Close-up of hands typing on a laptop keyboard, Python book in sight, coding in progress.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python poplib: Read Email with POP3

    Learn Python poplib to access POP3 with TLS, list and download messages, use UIDL, enforce limits, and avoid accidental deletion.

    Ler mais

    Tempo de leitura: 5 minutos
    22/08/2026
    Close-up of hands typing on a laptop keyboard, Python book in sight, coding in progress.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python imaplib: Read Email with IMAP

    Learn Python imaplib to access IMAP mailboxes with TLS, search by UID, read without marking messages, manage flags, and avoid

    Ler mais

    Tempo de leitura: 5 minutos
    22/08/2026
    Extreme close-up of computer code displaying various programming terms and elements.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python ftplib: Secure FTP and FTPS

    Learn Python ftplib to list, download, and upload files over FTP or FTPS with TLS, timeouts, limits, resume, and clear

    Ler mais

    Tempo de leitura: 5 minutos
    21/08/2026
    Server rack representing an endpoint built with Python xmlrpc.server
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    xmlrpc.server: Build XML-RPC Servers

    Learn Python xmlrpc.server to build XML-RPC servers, register functions, restrict methods and paths, and avoid unsafe exposure.

    Ler mais

    Tempo de leitura: 5 minutos
    21/08/2026
    Server cables representing remote calls with Python xmlrpc.client
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python xmlrpc.client: Remote Calls

    Learn Python xmlrpc.client to call XML-RPC services, handle Fault and ProtocolError, use TLS, compatible types, and safe limits.

    Ler mais

    Tempo de leitura: 5 minutos
    21/08/2026