Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Python  Module 6 – Modules, packages and the standard library

Packages, __init__.py and relative imports

Organise Python modules into packages with __init__.py, write absolute and relative imports, run package code with python -m, and import the right name.

  • Intermediate
  • 20 minutes
  • Examples run with Python 3.14.8 and Pyodide 314.0.7
  • By MySmartCoPilot
Free lesson, Pro answers: 20 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Organise modules into a package and predict which of its files an import runs
  • Resolve a relative import to the absolute module name it refers to
  • Run a module of a package with python -m from the right folder
  • Recognise a namespace package and the mistakes it can hide
  • Distinguish the name you install from the name you import

Before you start

What you’ll learn · Before you start

What you will learn

  • Organise modules into a package and predict which of its files an import runs
  • Resolve a relative import to the absolute module name it refers to
  • Run a module of a package with python -m from the right folder
  • Recognise a namespace package and the mistakes it can hide
  • Distinguish the name you install from the name you import

Before you start

On this page

Three modules about class marks, marks.py, students.py and reports.py, belong together, and a second project of yours may well have a reports.py of its own. A package: A folder of modules that is imported as one unit, such as school/ with school.marks and school.reports. A regular package has an __init__.py, which runs when anything of the package is first imported. puts them in one folder, school/, under one name: they become the modules school.marks, school.students and school.reports, and related code lives together instead of crowding the top level.

A regular package also has a file called __init__.py, which runs when the package is first imported and decides what import school gives you. Modules inside a package refer to each other with absolute import: An import that spells out a module's full dotted name from the top level, such as from school.marks import grade. It means the same thing in every file., which spell out the full name (from school.marks import grade), or relative import: An import that starts with dots, such as from .marks import grade. One dot is the package of the module that holds the import, and each extra dot goes up one package. Only the from form can be relative., which start from the module’s own package (from .marks import grade). Code that uses relative imports has to run as part of its package, and python -m school.reports is how you run it that way.

Importing a submodule loads its package first

This is the project of this lesson. main.py sits next to the school folder, and every file of the package has a module name made of the folder and the file:

The school_app folder holds main.py and the school package; each file of the package is labelled with its module name.school_app/ (run python here)main.pyruns as __main__school/ : the package school__init__.pyschool itself__main__.pyrun by python -m schoolreports.pyschool.reportsmarks.pyschool.marksstudents.pyschool.studentsimport school.marks.reports.marks.students

The files of the school package and their module names

Text description of the diagram

The diagram shows the folder school_app, where you run Python, and inside it two things.

  • main.py, which runs as the module __main__ when you start it, and imports the package with import school.
  • The folder school, which is the package school. Its files are: __init__.py, which is the package school itself; __main__.py, which python -m school runs; reports.py, the module school.reports; marks.py, the module school.marks; and students.py, the module school.students.
  • Arrows show the imports that import school runs, each labelled with the module it names: __init__.py imports from .marks and from .reports, and reports.py imports from .marks and from .students. The single dot means "this package", so .marks is school.marks.

main.py uses the package three ways: through the package itself, through a name the package re-exports, and through a submodule. The other tabs show the files of the package:

The school package

Python · school_app/main.py

import school
from school import report_card
from school.marks import grade

print(report_card("Ravi"))
print("Grade for 74.9:", grade(74.9))
print("Names:", school.__name__, "and", school.marks.__name__)
print("Public API:", school.__all__)

Output

Ravi: average 71.7, grade C
Grade for 74.9: C
Names: school and school.marks
Public API: ['average', 'grade', 'report_card']

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 main.py

school/__init__.py · school_app/school/__init__.py

"""A small package for class marks: averages, grades and report cards."""

from .marks import average, grade
from .reports import report_card

__all__ = ["average", "grade", "report_card"]

school/marks.py · school_app/school/marks.py

"""Averages and letter grades."""

GRADE_BANDS = [(90, "A"), (75, "B"), (60, "C"), (40, "D")]


def average(marks):
    return round(sum(marks) / len(marks), 1)


def grade(score):
    for lowest, letter in GRADE_BANDS:
        if score >= lowest:
            return letter
    return "E"

school/students.py · school_app/school/students.py

"""The class list (a real program would read it from a file)."""

STUDENTS = {
    "Asha": [92, 88, 95],
    "Ravi": [71, 64, 80],
    "Meera": [55, 62, 49],
}

school/reports.py · school_app/school/reports.py

"""Report cards, built from the other modules of the package."""

from .marks import average, grade
from .students import STUDENTS


def report_card(name):
    score = average(STUDENTS[name])
    return f"{name}: average {score}, grade {grade(score)}"


if __name__ == "__main__":
    print(report_card("Asha"))

school/__main__.py · school_app/school/__main__.py

"""What python -m school runs: a report card for every student."""

from .reports import report_card
from .students import STUDENTS

for name in sorted(STUDENTS):
    print(report_card(name))
  • Dotted names. A module inside a package is named after its path: school/marks.py is school.marks, and a subpackage school/reports/ with a cards.py in it would give school.reports.cards. Each part of the name except the last must be a package.
  • The package is a module too. import school creates a module object for the folder, whose code is __init__.py. Importing a submodule imports its packages first, so import school.marks runs school/__init__.py before marks.py, and binds marks as an attribute of school.
  • __init__.py sets the front door. This one imports report_card, average and grade from the submodules, so callers can write from school import report_card without knowing which file defines it. Its __all__ lists the public names; from school import * imports exactly those, and readers and tools treat the list as the package’s interface.

Which files ran for those three lines, and in what order? Step through them file by file:

Interactive · message by message What import school runs, file by file Step through the imports of main.py. An arrow is an import statement asking for a module; the sub-labels say what has loaded so far.
What import school runs, file by file, step 7 of 7. Messages so far: main.py to school/__init__.py: import school; school/__init__.py to The submodules: from .marks import; school/__init__.py to The submodules: from .reports import; school/__init__.py to main.py: school, report_card.main.pyschool, report_card, gradeschool/__init__.pyschool: completeThe submodulesmarks, reports, studentsimport schoolfrom .marks importfrom .reports importschool, report_card

The drawing shows the whole scene; its 7 steps are listed below.

Every step as text
  1. import school. Line 1 of main.py, import school, finds the folder school/ on sys.path. It holds an __init__.py, so school is a regular package, and Python loads the package first: a module named school whose code is __init__.py.
  2. The first line of __init__.py. __init__.py starts with from .marks import average, grade. The dot means this package, so Python loads school.marks: marks.py runs to its end.
  3. The second line. from .reports import report_card loads school.reports. reports.py starts running, and its own first line asks for .marks once more.
  4. Cached, then one more. school.marks is already in sys.modules, so reports.py gets average and grade without running marks.py again. Its next line loads school.students, and then reports.py finishes.
  5. The front door is ready. Back in __init__.py, average, grade and report_card are now names of the package, and __all__ lists them. Each submodule that was loaded is an attribute of the package too, such as school.marks.
  6. Names for main.py. import school binds the name school in main.py. Line 2, from school import report_card, finds the package in sys.modules and takes the name that __init__.py re-exported.
  7. Nothing new to load. Line 3, from school.marks import grade, finds school.marks in sys.modules as well. Four files ran, once each, in the order that load_order.py prints: school, school.marks, school.reports and school.students.

The order is not a guess. Python raises an A signal that Python sends at certain points while it runs, such as each time it loads a module. A function registered with sys.addaudithook() receives every one, with the event's name and its details. called import each time it loads a module, and this program collects those events while it imports the package:

Every module that import school loads Python · school_app/load_order.py
"""Which files of the package run, and in what order, when a program imports school."""
import sys

loaded = []


def watch(event, args):
    # Python raises the audit event "import" each time it loads a module.
    if event == "import" and args[0].startswith("school"):
        loaded.append(args[0])


sys.addaudithook(watch)

import school

print("import school loaded:", ", ".join(loaded))
loaded.clear()

from school import report_card
from school.marks import grade

print("the next two imports loaded:", ", ".join(loaded) or "nothing")
print("school.marks is an attribute of school:", hasattr(school, "marks"))

Output

import school loaded: school, school.marks, school.reports, school.students
the next two imports loaded: nothing
school.marks is an attribute of school: True

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 load_order.py

The four files loaded in the order of the figure, and the next two imports loaded nothing new. Press Edit, change import school to import school.students and run it again: the package still loads first, and its __init__.py still brings in the other three modules.

An empty __init__.py is fine and common. Whatever you put in it runs on the first import of anything in the package, so keep it to re-exports: a slow import or a file read in __init__.py slows down every program that touches one small submodule, and __init__.py files that import half the package are a frequent source of circular imports.

Key idea

Any import from a package runs its __init__.py first, once per program, so every program that uses one small module of the package also pays for whatever __init__.py imports.

Checkpoint

Check: What importing a package runs

  1. Question 1 of 2 A program runs only from school.marks import grade. Which files of the school package run?

    Choose one answer.

    A hint

    What must exist before Python can load school.marks?

    Show the answer: Question 1 of 2

    Answer: All four, __init__.py first, because it imports marks and reports, and reports imports students

    Python imports school before school.marks, which runs school/__init__.py. That file imports .marks and .reports, and reports.py imports .students, so all four files run, once each, before the program gets grade.

  2. Question 2 of 2 main.py runs import school and then uses school.marks.grade(74.9). It never imports school.marks itself. Why does that work?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: __init__.py imported .marks, and a loaded submodule is bound as an attribute of its package

    When a submodule is loaded, the import system binds it as an attribute of its parent package. school/__init__.py imports .marks, so after import school the name school.marks already refers to the module school.marks.

A relative import starts from the module’s own package

Inside school/reports.py, these pairs mean the same thing:

Relative import Absolute import Refers to
from .marks import grade from school.marks import grade school/marks.py
from . import students from school import students school/students.py
from .. import config (in school/reports/cards.py) from school import config school/config.py
  • One dot means the package that holds the current module; each extra dot goes up one package. In an __init__.py, the module is the package itself, so one dot means that package.
  • Only the from form can be relative: import .marks is a syntax error, because .marks could not be used as a name afterwards.
  • Relative imports follow the package, not the folder. Python works them out from the importing module’s package name, which it keeps in __package__. Going above the top-level package fails with “attempted relative import beyond top-level package”.

Before it searches for anything, Python turns a relative import into an absolute module name. Step through that conversion for from ..marks import grade inside school/reports/cards.py, the step the exercise of this lesson asks you to write:

Interactive · stage by stage From ..marks to school.marks Step through how Python works out a relative import before it searches for anything. Each stage is one rule.
From ..marks to school.marks, step 7 of 7. Showing from ..marks import, school.reports.cards, One dot: school.reports, Two dots: school, Then marks: school.marks, Import school.marks. In focus: One dot: school.reports, Two dots: school.from ..marks importin school/reports/cards.pyschool.reports.cardsthe module's own nameOne dot: school.reportsthe module's packageTwo dots: schoolup one packageThen marks: school.marksthe absolute nameImport school.marksthen bind gradethree dots: beyond the top-level package

The drawing shows the whole scene; its 7 steps are listed below.

Every step as text
  1. Two dots. from ..marks import grade starts with dots, so it is relative. Before it searches for anything, Python turns it into an absolute module name, using the name of the module that contains the import.
  2. Whose import is it?. The import is in school/reports/cards.py, the module school.reports.cards. Python keeps the package that module belongs to, school.reports, in its __package__.
  3. One dot is the package. The first dot means that package, school.reports. In an __init__.py the module is the package itself, so there one dot means the package whose file it is.
  4. Each extra dot goes up. The second dot goes up one package, from school.reports to school. A third dot would have to go above school, and there is nothing above a top-level package.
  5. The rest is added. What follows the dots, marks, is added to the end: school.marks. From here on the import is an ordinary absolute one, exactly as if it said from school.marks import grade.
  6. An ordinary import. Python imports school.marks through sys.modules and the folders of the package, and binds grade in cards.py. The dots were only a way of writing the full name.
  7. The two errors. Too many dots fail with "attempted relative import beyond top-level package". A file run by its path is __main__, with no package to start from, and fails with "attempted relative import with no known parent package".

Which should you write? Absolute imports are unambiguous and are what the official style guide, PEP 8, recommends by default. Relative imports are shorter inside a deep package and keep working if the whole package is renamed or moved inside another one. Many projects use absolute imports everywhere and relative ones only between modules of the same package; whichever you choose, use it consistently.

Checkpoint

Check: Relative and absolute imports

  1. Question 1 of 2 Inside school/reports/cards.py, which module does from . import layout import?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: school.reports.layout

    The module is school.reports.cards, so its package is school.reports. One dot means that package, and the name after it is added to the end, which gives school.reports.layout.

  2. Question 2 of 2 In school/__init__.py, which module does from .marks import grade import grade from?

    Choose one answer.

    A hint

    In an __init__.py, which module is the current module?

    Show the answer: Question 2 of 2

    Answer: school.marks

    In an ordinary module, one dot is the package around it. In an __init__.py the module is the package, so one dot means that package itself: from .marks inside school/__init__.py imports school.marks.

Run a module of a package by its name, not its path

reports.py has a small demo under its __name__ guard. Here are three ways of running files of the package, started from the school_app folder, with what each one printed:

Running files of the package Python · school_app/commands.py
"""Run files of the package three ways, as you would type them in a terminal."""
import subprocess
import sys


def run(typed, *args):
    print("$", typed)
    result = subprocess.run([sys.executable, *args], capture_output=True, text=True)
    if result.stderr:
        # The last line of a traceback, or a warning, says what went wrong.
        print(result.stderr.strip().splitlines()[-1])
    print(result.stdout, end="")


run("python school/reports.py", "school/reports.py")
run("python -m school.reports", "-m", "school.reports")
run("python -m school", "-m", "school")

Output

$ python school/reports.py
ImportError: attempted relative import with no known parent package
$ python -m school.reports
<frozen runpy>:130: RuntimeWarning: 'school.reports' found in sys.modules after import of package 'school', but prior to execution of 'school.reports'; this may result in unpredictable behaviour
Asha: average 91.7, grade A
$ python -m school
Asha: average 91.7, grade A
Meera: average 55.3, grade D
Ravi: average 71.7, grade C

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 commands.py

The second command printed a warning before the report card. Step through what -m did, and watch reports.py run twice under two names:

Interactive · message by message python -m school.reports, step by step Step through the command. runpy is the module that carries out -m; the sub-labels say how each file was run.
python -m school.reports, step by step, step 6 of 6. Messages so far: python -m to school/__init__.py: import school; school/__init__.py to school/reports.py: from .reports import; python -m to school/reports.py: run as __main__.python -mwarns, then goes onschool/__init__.pyschool: completeschool/reports.pyran again as __main__import schoolfrom .reports importrun as __main__

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. A module by name. You type python -m school.reports in school_app/. -m puts the current folder first on sys.path and finds the module by its dotted name, which means importing the package school first.
  2. The package loads. Importing the package runs school/__init__.py. Its second line, from .reports import report_card, needs school.reports.
  3. reports.py, the first time. school/reports.py runs under its real name, school.reports. Its __name__ is 'school.reports', so the guarded demo does not run, and __init__.py gets report_card.
  4. The warning. Back in runpy, the module it was asked to run is already in sys.modules. That is the RuntimeWarning in the output: the file is about to run a second time, which may lead to unpredictable behaviour.
  5. reports.py, the second time. runpy runs reports.py again, this time as __main__ with __package__ set to "school", so its relative imports resolve. The guard is true now, and the demo prints Asha: average 91.7, grade A.
  6. Two copies of one file. The file now backs two modules, school.reports and __main__, each with its own top-level variables. Keep entry points out of what __init__.py imports, or put them in __main__.py.

  • python school/reports.py fails. Run by its path, the file becomes the top-level module __main__, which belongs to no package, so its first relative import has nothing to start from. Python also puts school/ itself at the front of sys.path, so even an absolute from school.marks import grade would not find the package.
  • python -m school.reports works. -m searches sys.path for the module by name, imports its packages first (running school/__init__.py) and then runs the file as __main__ with __package__ set to "school", so the dots resolve. With -m, the first entry of sys.path is the current folder, so run it from the folder that contains school/.
  • The warning is worth reading. __init__.py had already imported school.reports to re-export report_card, so Python ran that file twice: once as school.reports and once as __main__. Two copies of a module also mean two copies of its top-level variables, which leads to confusing bugs in bigger programs. Keep entry points out of what __init__.py imports, or put them in __main__.py.
  • python -m school runs school/__main__.py. That file is the package’s command-line entry point. The documentation recommends keeping it short and without a __name__ guard: it imports what it needs and runs.

The browser runner cannot type a command, but the runpy module, which -m uses, does the same thing from Python:

python -m school, from inside Python Python · school_app/run_main.py
"""What python -m school does, from inside Python: runpy runs the package's __main__.py."""
import runpy

# run_module() returns the globals of the code it ran, which this program does not need.
names = runpy.run_module("school", run_name="__main__")

Output

Asha: average 91.7, grade A
Meera: average 55.3, grade D
Ravi: average 71.7, grade C

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 run_main.py

Checkpoint

Check: Running a module with python -m

  1. Question 1 of 2 From which folder must you type python -m school.reports?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: The folder that contains school/, such as school_app

    python -m finds the module by its dotted name through sys.path, and with -m the first entry of sys.path is the current folder. So run it from the folder above the package, where school/ is found.

  2. Question 2 of 2 Why did python -m school.reports print a RuntimeWarning before the report card?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: __init__.py had already imported school.reports, so the file was about to run a second time, as __main__

    runpy, which carries out -m, imported the package school, whose __init__.py imported school.reports. When it then ran reports.py as __main__, it found school.reports already in sys.modules and warned that one file was running twice, under two names.

A folder without an init file imports as a namespace package

A folder without __init__.py can still be imported. It becomes a namespace package: A package without an __init__.py (PEP 420). It has no code of its own and no __file__, and its parts may come from several folders on sys.path. Python makes one only when no module or regular package of that name exists. (PEP 420): a package with no code of its own and no __file__, whose parts may even come from several folders on sys.path. Large projects use them to ship separate distributions under one name, such as plugins that install into a shared namespace.

A namespace package, and a folder called json

Python · namespace/main.py

import json

import plugins.summary

with open("json/marks.json", encoding="utf-8") as file:
    marks = json.load(file)  # the standard library's json: the folder has no __init__.py

print(plugins.summary.describe(marks))
print("plugins.__file__ is", plugins.__file__)
print("plugins.__path__ is a", type(plugins.__path__).__name__)

Output

3 students; top mark 92 (Asha)
plugins.__file__ is None
plugins.__path__ is a _NamespacePath

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 main.py

plugins/summary.py · namespace/plugins/summary.py

def describe(marks):
    best = max(marks, key=marks.get)
    return f"{len(marks)} students; top mark {marks[best]} ({best})"

json/marks.json · namespace/json/marks.json

{"Asha": 92, "Ravi": 71, "Meera": 55}

This folder holds two folders without __init__.py, and they end up very differently. Step through the search that each import makes:

Interactive · step by step Two folders without __init__.py Step through import json and import plugins. The left column is the script's folder, first on sys.path; the right one is the standard library.
Two folders without __init__.py, step 7 of 7. Showing main.py, The standard library, json/ (ignored: json was found), json/, plugins/ (namespace package plugins), No plugins here. In focus: main.py, plugins/.import jsonkeeps searchingmain.pyimports json, pluginsThe standard librarysearched nextjson/ignored: json was foundjson/has __init__.pyplugins/namespace package pluginsNo plugins herenor anywhere else

The drawing shows the whole scene; its 7 steps are listed below.

Every step as text
  1. import json. main.py starts with import json. Python searches sys.path in order, and the first folder, the script's own, holds a folder called json.
  2. Noted, not taken. That folder has no __init__.py, so it is not a regular package. Python notes it as a possible part of a namespace package and keeps searching the rest of sys.path.
  3. The real json wins. In the standard library it finds json/ with an __init__.py, a regular package. A regular package ends the search at once, so json is the standard module and json.load() reads marks.json.
  4. import plugins. import plugins.summary imports plugins first. The script folder holds plugins/ without an __init__.py, so it is noted, and the search goes on.
  5. Nothing else. No other folder of sys.path has a module, a regular package or even a folder called plugins. The noted folder is all there is.
  6. A namespace package. At the end of the search the noted folders become one namespace package. plugins has no code of its own, so its __file__ is None, and its __path__ is a _NamespacePath, as the output shows.
  7. A module inside. summary.py in that folder is an ordinary module, plugins.summary. Its describe() prints the first line of the output: 3 students; top mark 92 (Asha).

plugins imported without an __init__.py; its __file__ is None and its __path__ is a special sequence of folders that Python searches again when the folders on sys.path change. The json folder shows the other side of the rule: a folder without __init__.py never hides a real module or package. Python remembers such a folder as a possible namespace package and keeps searching, and the standard library’s json module, found later, wins. That differs from a file called json.py, which would hide it, as the previous lesson showed.

The convenience has a cost. Any folder on sys.path can be imported, so an import that meets a stray folder of the same name, such as a folder of data files or one left over after a rename, gives you an empty package instead of a clear ModuleNotFoundError, and the mistake only shows up later as an AttributeError. Give your own packages an __init__.py, even an empty one, and keep namespace packages for the plugin case.

Checkpoint

Check: Namespace packages

  1. One question A folder holds main.py and a folder json/ without an __init__.py. main.py runs import json. Which json does it get?

    Choose one answer.

    Show the answer: One question

    Answer: The standard library's json, because a folder without __init__.py is only noted while the search goes on

    A folder without __init__.py is noted as a possible part of a namespace package, and the search goes on. The standard library's json is a regular package, which ends the search, so the folder is ignored, as the example's output showed.

The name you install is not always the name you import

Packages on PyPI are distribution package: A project as pip installs it, under its name on PyPI, such as pillow. It holds one or more import packages, whose names may differ from it: pillow is imported as PIL.: the name you give to pip install. What your code imports is an import package, and nothing forces the two names to match:

You install You import Why
pip install requests import requests most projects keep the two names equal
pip install pillow from PIL import Image Pillow began as a fork of an older library called PIL and kept its import name

The packaging guide calls matching names only a convention: the package index does not enforce any link between the two, and one distribution can even provide several import packages. So when you see an import you do not recognise, look it up in the project’s documentation before installing a package of that name: a package with the matching name may be a different project, or one made to catch exactly that guess.

Checkpoint

Check: The name you install and the name you import

  1. One question A script you were given starts with import yaml, and nobody told you what to install. What should you do first?

    Choose one answer.

    Show the answer: One question

    Answer: Look up the project in its own documentation, which says which distribution to install

    What you install is a distribution package, named on PyPI; what you import is an import package, and the two names need not match. Check the project's documentation before installing a package with a guessed name.

Python Online Compiler Import json.decoder and print its __name__ and __package__ to see a submodule's dotted name and the package it belongs to.

Practise: work out a relative import

Before it searches for anything, Python turns every relative import into an absolute module name, using the name of the module that contains it. Write that step yourself, with both of its error messages, and the dots of a relative import stop being guesswork.

Exercise · Medium · Python

Work out what a relative import refers to

Write absolute_name(module, dots, name="", is_package=False), which returns the absolute module name that a relative import refers to, the way Python works it out:

  • module is the full name of the module that contains the import, such as "school.reports".
  • dots is the number of leading dots (1 or more) and name is what follows them, so from ..marks import grade inside school.reports.cards is absolute_name("school.reports.cards", 2, "marks"), which gives "school.marks". For from . import marks, name is "".
  • One dot means the package that holds the module; each extra dot goes up one more package. In school.reports, that package is school. When the module is itself a package (its code is an __init__.py), is_package is True and one dot means that package: absolute_name("school", 1, "marks", is_package=True) is "school.marks".
  • A module with no package around it ("main", or "__main__" when a file is run as a script) raises ImportError("attempted relative import with no known parent package").
  • Going up past the top-level package raises ImportError("attempted relative import beyond top-level package").

The sample tests import your function from relative.py.

Starter code · relative.py

def absolute_name(module, dots, name="", is_package=False):
    """The absolute module name that `from <dots><name> import ...` inside `module` refers to."""
    # Replace this line with your code.
    return name
The sample tests · test_relative.py
from relative import absolute_name


def error_message(*args, **kwargs):
    """The message of the ImportError that absolute_name raises (None if it raises nothing)."""
    try:
        absolute_name(*args, **kwargs)
    except ImportError as error:
        return str(error)
    return None


def test_one_dot():
    """one dot is the package that holds the module"""
    assert absolute_name("school.reports", 1, "marks") == "school.marks"
    assert absolute_name("school.reports.cards", 1, "layout") == "school.reports.layout"


def test_dot_alone():
    """from . import x refers to the package itself"""
    assert absolute_name("school.reports", 1) == "school"
    assert absolute_name("school.reports.cards", 2) == "school"


def test_two_dots():
    """each extra dot goes up one package"""
    assert absolute_name("school.reports.cards", 2, "marks") == "school.marks"
    assert absolute_name("app.ui.forms.fields", 3, "config.paths") == "app.config.paths"


def test_package_init():
    """in an __init__.py, one dot is the package itself"""
    assert absolute_name("school", 1, "marks", is_package=True) == "school.marks"
    assert absolute_name("school.reports", 1, "cards", is_package=True) == "school.reports.cards"
    assert absolute_name("school.reports", 2, "marks", is_package=True) == "school.marks"


def test_no_parent_package():
    """a module outside any package cannot use a relative import"""
    assert error_message("main", 1, "utils") == "attempted relative import with no known parent package"
    assert error_message("__main__", 1) == "attempted relative import with no known parent package"


def test_beyond_top_level():
    """going above the top-level package is an error"""
    assert error_message("school.reports", 2, "marks") == "attempted relative import beyond top-level package"
    assert error_message("school", 2, "x", is_package=True) == "attempted relative import beyond top-level package"
    assert error_message("school.reports", 1, "marks") is None
A hint

Start from the package: module.split(".") gives the parts, and the package is all of them except the last one, or all of them when is_package is True. An empty package means "no known parent package". Then each dot after the first removes one more part from the end; if you need to remove more parts than there are, the import goes beyond the top-level package. Join what is left, and add name when it is not empty.

The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Fourteen questions follow on the five ideas of this lesson. They come one at a time, starting from the idea where your answers so far are weakest, and each one shows its reasoning as soon as you check it:

Practice that adapts to you

Practise this lesson

14 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 14 A folder school/ holds marks.py and reports.py. What makes it a regular package?

    Choose one answer.

    Show the answer: Question 1 of 14

    Answer: An __init__.py file in the folder

    A regular package is a folder with an __init__.py file, which runs when the package is first imported. A folder without one can still be imported, but as a namespace package, which has no __init__.py code and no __file__. __main__.py only matters for python -m.

  2. Question 2 of 14 What does load_order.py print?

    What does this program print? Choose one answer.

    """Which files of the package run, and in what order, when a program imports school."""
    import sys
    
    loaded = []
    
    
    def watch(event, args):
        # Python raises the audit event "import" each time it loads a module.
        if event == "import" and args[0].startswith("school"):
            loaded.append(args[0])
    
    
    sys.addaudithook(watch)
    
    import school
    
    print("import school loaded:", ", ".join(loaded))
    loaded.clear()
    
    from school import report_card
    from school.marks import grade
    
    print("the next two imports loaded:", ", ".join(loaded) or "nothing")
    print("school.marks is an attribute of school:", hasattr(school, "marks"))
    Show the answer: Question 2 of 14

    Answer: it prints

    import school loaded: school, school.marks, school.reports, school.students
    the next two imports loaded: nothing
    school.marks is an attribute of school: True

    Python raises the audit event import each time it loads a module. import school loads the package, and its __init__.py loads school.marks and school.reports, which loads school.students. The later imports load nothing new, and school.marks is an attribute of the package.

  3. Question 3 of 14 school/__init__.py gains a line that reads a 50 MB file of past results whenever it runs. Which programs get slower?

    Choose one answer.

    Show the answer: Question 3 of 14

    Answer: Every program that imports anything of the package, even one that only needs school.marks

    Whatever __init__.py does happens on the first import of anything in the package, in every program. That is why an __init__.py should only re-export names and leave slow work to the functions that need it.

  4. Question 4 of 14 Inside school/reports/cards.py, which module does from ..marks import grade import grade from?

    Choose one answer.

    Show the answer: Question 4 of 14

    Answer: school.marks

    The module is school.reports.cards, so its package is school.reports. One dot means that package and the second dot goes up one more, to school, so ..marks is school.marks.

  5. Question 5 of 14 Which of these is a valid relative import?

    Choose one answer.

    Show the answer: Question 5 of 14

    Answer: from .marks import grade

    A relative import always has the form from <dots><module> import <names>. import .marks is a syntax error, because the import statement would have to bind a name that starts with a dot.

  6. Question 6 of 14 In school/reports.py, the module school.reports, what happens at from ..marks import grade?

    Choose one answer.

    Show the answer: Question 6 of 14

    Answer: ImportError: attempted relative import beyond top-level package

    The package of school.reports is school, so one dot means school and two dots would mean the package above it, which does not exist. Python refuses with "attempted relative import beyond top-level package".

  7. Question 7 of 14 The package school is renamed to classroom. Which imports between its own modules keep working without an edit?

    Choose one answer.

    Show the answer: Question 7 of 14

    Answer: The relative ones, such as from .marks import grade

    An absolute import spells out the package's name, so renaming the package breaks it. A relative import starts from wherever the module is, so it keeps working when the package is renamed or moved inside another one.

  8. Question 8 of 14 python school/reports.py stops with ImportError: attempted relative import with no known parent package. What is the usual fix?

    Choose one answer.

    Show the answer: Question 8 of 14

    Answer: Run python -m school.reports from the folder that contains school/

    A file run by its path becomes the module __main__ with no package, so relative imports have nothing to start from. python -m school.reports imports the package first and runs reports.py as part of it, which gives the dots their meaning. Run it from the folder above school/, because -m puts the current folder first on sys.path.

  9. Question 9 of 14 What does commands.py print for the three commands?

    What does this program print? Choose one answer.

    """Run files of the package three ways, as you would type them in a terminal."""
    import subprocess
    import sys
    
    
    def run(typed, *args):
        print("$", typed)
        result = subprocess.run([sys.executable, *args], capture_output=True, text=True)
        if result.stderr:
            # The last line of a traceback, or a warning, says what went wrong.
            print(result.stderr.strip().splitlines()[-1])
        print(result.stdout, end="")
    
    
    run("python school/reports.py", "school/reports.py")
    run("python -m school.reports", "-m", "school.reports")
    run("python -m school", "-m", "school")
    Show the answer: Question 9 of 14

    Answer: it prints

    $ python school/reports.py
    ImportError: attempted relative import with no known parent package
    $ python -m school.reports
    <frozen runpy>:130: RuntimeWarning: 'school.reports' found in sys.modules after import of package 'school', but prior to execution of 'school.reports'; this may result in unpredictable behaviour
    Asha: average 91.7, grade A
    $ python -m school
    Asha: average 91.7, grade A
    Meera: average 55.3, grade D
    Ravi: average 71.7, grade C

    Run by its path, reports.py has no package, so its relative import fails. With -m it runs inside the package, but __init__.py had already imported school.reports, so Python warns that the file now runs a second time as __main__. python -m school runs the package's __main__.py, which prints a card for every student.

  10. Question 10 of 14 What does python -m school run?

    Choose one answer.

    Show the answer: Question 10 of 14

    Answer: school/__main__.py, after importing the package

    python -m school imports the package, which runs __init__.py, and then runs school/__main__.py as __main__. That is why the third command of commands.py printed a card for every student.

  11. Question 11 of 14 What is __file__ of a namespace package such as plugins?

    Choose one answer.

    Show the answer: Question 11 of 14

    Answer: None

    A namespace package is made from folders alone, so it has no file of code: its __file__ is None, and its __path__ is a _NamespacePath that lists the folders it was made from.

  12. Question 12 of 14 An empty folder reprots/ was left in a project, and some code mistypes an import as import reprots. What happens?

    Choose one answer.

    Show the answer: Question 12 of 14

    Answer: It imports an empty namespace package, and the mistake shows up later as an AttributeError

    A folder without __init__.py imports as a namespace package even when it is empty, so the misspelt import works and gives a package with nothing in it. The error comes later, when code asks it for a name. Give your own packages an __init__.py, even an empty one.

  13. Question 13 of 14 You install the imaging library with pip install pillow. What do you write in your code?

    Choose one answer.

    Show the answer: Question 13 of 14

    Answer: from PIL import Image

    The name you install (the distribution name on PyPI) and the name you import are separate things. Pillow began as a fork of an older library called PIL and kept its import name, so you install pillow and import PIL.

  14. Question 14 of 14 A colleague sees from PIL import Image and types pip install PIL. What is the risk?

    Choose one answer.

    Show the answer: Question 14 of 14

    Answer: PIL is not the name the library is installed under, and a package with the guessed name could be a different project

    The import name tells you what the code imports, not what to install. Go by the project's documentation, which says pip install pillow, rather than installing whatever is published under the guessed name.

Interview questions

Fresher · Why does from . import utils fail when you run the file directly, and how do you run it instead?

A relative import is resolved against the package of the module that contains it, which Python keeps in __package__. When you run a file by its path, as in python app/cli.py, Python runs it as the top-level module __main__, which belongs to no package, so the dot has nothing to start from and the import fails with “attempted relative import with no known parent package”. Run it as a module of its package instead: from the folder that contains app/, type python -m app.cli. Python then imports app first, running its __init__.py, and runs cli.py with __package__ set to "app", so .utils means app.utils. Rewriting the import as from app import utils does not rescue the direct run, because the folder that contains app/ is still not on sys.path.

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Mid to senior

    Importing one small module of your team's package, mypkg.textutils, takes 1.8 seconds. mypkg/__init__.py imports every submodule so that users can write from mypkg import Report. How do you confirm where the time goes, and how do you make the import fast without breaking that line?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Mid to senior

    A nightly job is started with python -m shop.orders. Its log shows the start-up line twice, a RuntimeWarning mentions sys.modules, and a counter in shop/orders.py differs between the job and the modules that import it. Explain what is happening and how you would restructure the entry point.

    Model answer, Pro. First step and follow-ups

Key takeaways

  • A package is a folder of modules with an __init__.py; its modules get dotted names such as school.marks, and importing one runs the package’s __init__.py first.
  • Keep __init__.py light, because every import from the package runs it: re-export the public names and list them in __all__.
  • Relative imports (from .marks import grade) work only in the from form and only inside a package; one dot is the current package and each extra dot goes up one.
  • Run code that lives in a package with python -m package.module from the folder above the package, and python -m package runs its __main__.py.
  • A folder without __init__.py is a namespace package: it never hides a real module, but it imports even when empty.
  • The PyPI name and the import name can differ (pillow and PIL), so check the project’s documentation before you install a guess.

Terms in this lesson

absolute import
An import that spells out a module's full dotted name from the top level, such as from school.marks import grade. It means the same thing in every file.
distribution package
A project as pip installs it, under its name on PyPI, such as pillow. It holds one or more import packages, whose names may differ from it: pillow is imported as PIL.
namespace package
A package without an __init__.py (PEP 420). It has no code of its own and no __file__, and its parts may come from several folders on sys.path. Python makes one only when no module or regular package of that name exists.
package
A folder of modules that is imported as one unit, such as school/ with school.marks and school.reports. A regular package has an __init__.py, which runs when anything of the package is first imported.
relative import
An import that starts with dots, such as from .marks import grade. One dot is the package of the module that holds the import, and each extra dot goes up one package. Only the from form can be relative.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.