PEP 8, section by section

Python Imports Style: Order, Grouping, Absolute vs Relative and Wildcards

PEP 8, section by section · · Published 2026-10-27

Aerial view of a large container port with green gantry cranes and long rows of stacked shipping containers
Container cranes and stacked containers at the port of Tacoma, seen from the air. Photo: Brian Harris, US Army, public domain.

The import block is the first thing a reader sees in a module, and it tells them what the code depends on. PEP 8's rules for it are short and almost entirely mechanical, which is why they are among the easiest to automate.

One module per line

PEP 8 asks for imports "on separate lines":

import sys, os
import os
import sys
from subprocess import PIPE, Popen

Importing several names from one module on a single line is explicitly allowed. The rule is about readability and diffs: removing os later changes one line instead of editing a list. pycodestyle reports the first form as E401 (multiple imports on one line).

At the top of the file, in a fixed order

Imports "are always put at the top of the file, just after any module comments and docstrings, and before module globals and constants". The expected layout of a module's head is:

"""Export invoices as CSV files."""

from __future__ import annotations

__all__ = ["export_invoices"]
__version__ = "1.2"

import csv
import datetime as dt
from pathlib import Path

import requests

from billing.models import Invoice
from billing.utils import money

A few points from PEP 8 are visible here:

pycodestyle reports an import that appears at module level after other code as E402 (module level import not at top of file). It tolerates a docstring, dunder assignments and conditional blocks such as try/except ImportError before imports, and it does not complain about imports inside functions, which PEP 8 does not forbid. Local imports are a legitimate tool for breaking an import cycle or delaying an expensive import until it is needed, though they also hide a dependency from the top of the module.

Absolute or relative?

PEP 8 recommends absolute imports because "they are usually more readable and tend to be better behaved (or at least give better error messages)" when the import system is misconfigured. Inside a package, explicit relative imports are "an acceptable alternative", especially in deep package layouts where absolute paths become verbose:

# Absolute
from billing.models import Invoice

# Explicit relative, from a module inside the billing package
from .models import Invoice
from . import utils

The standard library itself always uses absolute imports. Implicit relative imports, where import models silently meant a sibling module, were removed in Python 3 following PEP 328; the leading dot is now required.

When importing a class, from myclass import MyClass is usually fine. If that causes a name clash, import the module and qualify the name: import myclass, then myclass.MyClass. The same applies to modules whose names are clearer with their prefix, such as datetime.date versus a local date variable.

Wildcard imports

from module import * should be avoided, PEP 8 says, because it makes it "unclear which names are present in the namespace, confusing both readers and many automated tools". A linter cannot tell whether a name is defined or misspelled when a wildcard might have provided it; pyflakes, and therefore flake8 and ruff, report undefined names that may come from a star import as F405.

The guide allows one defensible use: republishing an internal interface as part of a public API, for example when an optional accelerated module replaces pure-Python definitions. In that case, the module being star-imported should define __all__, which controls exactly what import * exports.

Sorting imports automatically

PEP 8 defines the three groups but says nothing about the order inside each group. Tools fill that gap, usually by sorting alphabetically, with plain import x statements and from x import y statements arranged according to their settings. The two common choices are isort, a dedicated import sorter, and ruff, whose I rules reimplement isort's behaviour. Given this unsorted block:

import sys, os
import requests
from myapp.models import Invoice
import json

running ruff check --select I,E401 --fix produced:

import json
import os
import sys

import requests
from myapp.models import Invoice

Notice that myapp ended up in the third-party group. The tool cannot know which top-level packages are yours unless it is told, either by detecting your project's source directory or through a setting such as isort's known_first_party (also available in ruff's isort options). If imports keep landing in the wrong group, that setting is usually the cause.

When using isort alongside black, its documentation provides a black profile so that the two tools agree on line wrapping. Our article on ruff covers configuring import sorting there.

Imports and type checking

Type hints add one more pattern. A module that is only needed for annotations, and would create an import cycle at runtime, can be imported under if TYPE_CHECKING:, a constant from the typing module that is false at runtime and treated as true by type checkers. Combined with from __future__ import annotations or, from Python 3.14, the default deferred evaluation of annotations, this keeps the runtime import graph small. Use it sparingly: it is a fix for cycles and expensive imports, not a default.

Checklist

  1. Docstring first, then from __future__ imports, then dunders, then imports.
  2. One module per import line; group standard library, third party, local.
  3. Absolute imports by default; explicit relative imports inside large packages.
  4. No wildcard imports, except to re-export with a defined __all__.
  5. Let a tool sort the block, and tell it which packages are first-party.

The checker on our home page reports E401 and E402. For the rest of the guide, start with our section-by-section overview of PEP 8.

Sources