Imports

Imports let you reuse code from other modules and packages instead of rewriting it from scratch. Imports help keep your project modular, testable, and maintainable.

Clear, organized, and consistent imports allow you to spot a module’s dependencies at a glance. Key points for good imports include avoiding circular imports and name clashes.

For imports, the following best practices make dependencies easier to understand and maintain:

  • Prefer explicit imports with clear origins. Use absolute imports (for example, from app.utils import helpers) when referring to modules outside your current package, as they make it clear where each name comes from and are resilient to refactoring. Within a package, explicit relative imports like from . import helpers are idiomatic and help communicate internal relationships.
  • Group and order imports consistently. Group imports into three sections: standard library, third-party, and local application imports, separated by blank lines. Within each group, sort imports alphabetically. This follows PEP 8’s recommendations and improves readability.
  • Avoid wildcard imports. Don’t use from module import * in production code. Wildcard imports obscure where names come from, make static analysis harder, and can accidentally overwrite existing names in your namespace. They are mainly intended for interactive use or carefully controlled package APIs.
  • Be deliberate when importing individual names. Importing a module (for example, import math) makes it explicit where names come from and avoids namespace clutter when using many attributes. Importing specific names (from math import sqrt) can still be appropriate when those names are central to the module’s purpose or part of a well-defined public API.
  • Keep imports at the top. Place imports at the top of the file, after module docstrings and before any other code, unless you have a specific reason for a local import, such as avoiding a circular dependency or reducing import time.
  • Avoid circular imports. If two modules import each other, refactor to reduce coupling or move shared code into a separate module. Circular imports can lead to confusing errors, such as accessing attributes on a partially initialized module.
  • Use tools to manage imports automatically. Tools like isort and Ruff can automatically sort and validate imports, enforcing consistency and reducing manual effort.

To see these ideas in practice, consider the following hypothetical module:

🔴 Avoid this:

Python report.py
from app.utils.helpers import format_date, slugify
import requests, os, sys
from .models import *
import json

def get_data():
    # Call the API here...

def build_report(data):
    # Generate report here...

This module mixes import styles, uses a wildcard import, and combines unrelated imports on a single line. It also doesn’t follow standard grouping conventions, making the module’s dependencies harder to scan and reason about.

Favor this:

Python report.py
import json
import os
import sys

import requests

from app.utils import helpers
from . import models

def get_data():
    # Call the API here...

def build_report(data):
    # Generate report here...

In this version, imports are grouped and ordered clearly: standard library (json), third-party (requests), and local application imports (app.utils, .models). Wildcard imports are removed, and each imported name has a clear, explicit origin. Referring to the helpers and models modules directly keeps the namespace clean while remaining flexible as those modules evolve.

Tutorial

Python import: Advanced Techniques and Tips

The Python import system is as powerful as it is useful. In this in-depth tutorial, you'll learn how to harness this power to improve the structure and maintainability of your code.

intermediate python stdlib

For additional information on related topics, take a look at the following resources:


By Leodanis Pozo Ramos • Updated Dec. 23, 2025 • Reviewed by Brenda Weleschuk and Bartosz Zaczyński