Absolute vs relative python imports

PYTHON Published Updated 3 mins read By Leon Wei
Absolute vs relative python imports cover image

Quick summary

Summarize this blog with AI

An absolute import names a module from the import search path. An explicit relative import starts with dots and is resolved using the current package. A filesystem-relative filename and a package-relative import are different things. This lesson supplies one complete package and tests it from two working directories using Python 3.12.14.

Create the same tiny package for every experiment

Create a new project folder containing the files below. The package initializer is an empty UTF-8 file named demo_pkg/__init__.py. No third-party dependencies are required.

project/
  demo_pkg/
    __init__.py
    numbers.py
    report.py

demo_pkg/numbers.py:

def total(values):
    return sum(values)

demo_pkg/report.py demonstrates both import forms. It does not print when imported normally:

from demo_pkg.numbers import total as absolute_total
from .numbers import total as relative_total

def main():
    print(absolute_total([2, 3]), relative_total([2, 3]))

if __name__ == "__main__":
    main()

Run a module with its package context

From inside project, run:

python -m demo_pkg.report

Expected output:

5 5

The project directory is available for import, so Python finds demo_pkg and executes report with package context. Absolute imports use the full package path; from .numbers uses the sibling module in that package. A leading dot does not mean “whatever happens to be in my current working directory.”

Why direct script execution differs

From the same directory, python demo_pkg/report.py normally fails at the absolute import because the script directory, rather than its parent project directory, leads the search path. If you separately make demo_pkg importable, the explicit relative import still needs package context and can fail with “attempted relative import with no known parent package.” Use -m for this package entry point; do not paste sys.path mutations into every module.

The next reproducible probe creates the files in a temporary directory, strips inherited PYTHONPATH and PYTHONHOME settings for controlled tests, and compares two working directories. The supplied module code is repeated here so this probe is independently runnable.

from pathlib import Path
from tempfile import TemporaryDirectory
import os
import subprocess
import sys

with TemporaryDirectory() as temporary:
    root = Path(temporary)
    project = root / "project"
    package = project / "demo_pkg"
    package.mkdir(parents=True)
    (package / "__init__.py").write_text("", encoding="utf-8")
    (package / "numbers.py").write_text(
        "def total(values):\n    return sum(values)\n", encoding="utf-8")
    (package / "report.py").write_text(
        "from demo_pkg.numbers import total as absolute_total\n"
        "from .numbers import total as relative_total\n"
        "def main():\n    print(absolute_total([2, 3]), relative_total([2, 3]))\n"
        "if __name__ == '__main__':\n    main()\n", encoding="utf-8")
    environment = dict(os.environ)
    for key in ("PYTHONPATH", "PYTHONHOME"):
        environment.pop(key, None)
    def run(arguments, cwd, extra_path=None):
        selected = dict(environment)
        if extra_path is not None:
            selected["PYTHONPATH"] = str(extra_path)
        return subprocess.run([sys.executable, *arguments], cwd=cwd,
            env=selected, capture_output=True, text=True, timeout=5)
    normal = run(["-m", "demo_pkg.report"], project)
    direct = run(["demo_pkg/report.py"], project)
    outside = run(["-m", "demo_pkg.report"], root)
    explicit = run(["-m", "demo_pkg.report"], root, project)
    direct_with_path = run(["demo_pkg/report.py"], project, project)
    print("module:", normal.returncode, normal.stdout.strip())
    print("direct fails:", direct.returncode != 0)
    print("outside fails:", outside.returncode != 0)
    print("explicit search path:", explicit.returncode, explicit.stdout.strip())
    print("direct still lacks package:", "no known parent package" in direct_with_path.stderr)

Expected output:

module: 0 5 5
direct fails: True
outside fails: True
explicit search path: 0 5 5
direct still lacks package: True

Use installation for a reusable project

The temporary PYTHONPATH override demonstrates the search-path rule for one child process; it is not advice to permanently modify the machine’s environment. A real reusable project should declare packaging metadata and be installed into the selected virtual environment, making its package available from other working directories. That still does not make direct file execution equivalent to -m.

Regular packages use an initializer as shown; namespace packages are a supported exception, so an initializer is not a universal requirement for all packages. Avoid filenames such as json.py or pandas.py that shadow the module you meant to import. Inspect module.__file__ and sys.executable when the wrong copy loads. Circular imports require restructuring dependencies, not trying absolute and relative syntax at random.

References and next steps

Python modules and packages, Import system package context, Module search path.

Interview Prep

Begin Your SQL, Python, and R Journey

Master 230 interview-style coding questions and build the data skills needed for analyst, scientist, and engineering roles.

Related Articles

All Articles
Python first match cover image
python Oct 17, 2026

Python first match

Master Python's First Match for string pattern searches. Efficiently locate the first occurrence of patterns in strings, a skill for log parsing…

Python pyqt gui calculator cover image
python Apr 29, 2024

Python pyqt gui calculator

Embark on GUI programming journey with PyQt in Python Discover how to create intuitive cross-platform applications from simple windows to fully-…

Python ordereddict cover image
python Apr 29, 2024

Python ordereddict

Discover how Python's OrderedDict maintains element order, offering key benefits for data tracking and serialization, especially in versions pri…