Python
import statement
leading dot
relative import
programming tutorial

What does a leading . dot, period in an import statement in Python mean?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

A leading dot in a Python import statement indicates a relative import, meaning the module path is resolved from the current package location. This is useful in larger codebases where modules inside the same package reference each other. Understanding relative imports prevents import errors, circular import confusion, and broken command line execution.

Core Sections

Relative import basics

In Python, from .module import name means import from the current package. from ..module import name means move up one package level first. Each additional dot moves one level higher in the package hierarchy.

python
1# project/layout
2# app/
3#   __init__.py
4#   services/
5#     __init__.py
6#     billing.py
7#   models/
8#     __init__.py
9#     invoice.py
10
11# inside app/services/billing.py
12from ..models.invoice import Invoice

That import works because billing.py is inside app.services, and ..models resolves to app.models.

Relative versus absolute imports

Absolute imports use a full package path from project root. Relative imports use dots based on the current module location.

python
1# absolute
2from app.models.invoice import Invoice
3
4# relative
5from ..models.invoice import Invoice

Absolute imports are often easier to search and refactor across repositories. Relative imports reduce repeated package prefixes inside tightly coupled subpackages. Teams usually pick one style guide and apply it consistently.

Why script execution often fails with relative imports

A common error appears when running a module directly as a script:

ImportError: attempted relative import with no known parent package

This happens when Python does not treat the file as part of a package context. Use module execution instead of direct file execution.

bash
# from repository root
python -m app.services.billing

Running with -m preserves package semantics, so relative imports resolve correctly.

Package structure requirements

Relative imports only work in real packages. In practice, that means your project should use installable package layout or a clear source root with package directories.

text
1src/
2  app/
3    __init__.py
4    services/
5      __init__.py
6      billing.py

Although modern Python supports namespace packages without __init__.py, many teams still include it explicitly for clarity and tooling compatibility.

Refactoring strategy for import stability

If import behavior feels brittle, consider these improvements:

  • define a stable top level package and install in editable mode during development.
  • avoid executing deep modules directly.
  • keep imports acyclic by moving shared logic into utility modules.
bash
pip install -e .

Editable installs make absolute imports predictable across local shells, tests, and CI jobs.

Testing import behavior

Import issues often appear only in one entry path, such as test runners or local scripts. Add a small smoke test that imports critical modules to catch regressions early.

python
1# tests/test_imports.py
2
3def test_import_paths():
4    from app.services import billing
5    assert billing is not None

This lightweight test detects broken package moves before runtime failures in production paths.

Common Pitfalls

  • Running package modules as standalone files and expecting relative imports to work. Use python -m package.module instead.
  • Mixing absolute and relative imports inconsistently across the same package. Adopt one convention and enforce it.
  • Moving modules without updating dot depth in relative imports. Recheck import paths after refactors.
  • Ignoring package structure and relying on ad hoc PYTHONPATH changes. Use installable project layout for stability.
  • Treating circular import failures as relative import syntax issues. Break cyclic dependencies with better module boundaries.

Summary

  • Leading dots in Python imports denote package relative resolution.
  • One dot means current package, two dots mean parent package.
  • Relative imports require package context and usually module execution with -m.
  • Consistent import style and clear package layout reduce runtime surprises.
  • Add import smoke tests to catch path regressions early.

Additional implementation notes: keep boundaries explicit, validate assumptions with tests, and prefer maintainable conventions over clever shortcuts when designing shared code paths.


Course illustration
Course illustration

All Rights Reserved.