Skip to content

Modules & packages

This page covers programs split across several files: import, from ... import, aliases with as, packages with __init__.py, relative imports, modules that import each other, and the if __name__ == "__main__" guard. The compiler looks for imported modules next to the file you compile, runs each module's top-level code once in the order it is first imported, and compiles every module it reaches into one compiled program file, .dbc. The machine that runs the program never needs the .py files, and no path from your computer is stored in the output.

Multi-file programs run on the CLI

The browser playground compiles one file at a time, so the samples on this page are excerpts rather than programs you can run there. They are tested with the dpython command-line compiler and the test suite; the corpus page lists the four multi-file test programs.

A sibling module

scoreboard.py:

# fragment: examples/modular/scoreboard.py
scores = [18, 7, 24, 11]

def record(value):
    scores.append(value)
    return len(scores)

def best():
    return max(scores)

main.py:

# fragment: examples/modular/main.py
import scoreboard
from scoreboard import best as top

print("Scores:", scoreboard.scores)
print("Best:", top())

import scoreboard, an alias with as, and from scoreboard import best all work, as long as the import sits at the top level of the file rather than inside an if or a function. scoreboard.scores always shows the module's current value; from scoreboard import best copies the value at the moment of the import, as in Python. A function you import keeps its own module's variables, its defaults and the variables it captured, even when it is called much later as a callback, for example as the handler for a window event.

Packages

# fragment: examples/packages/main.py
from scoreboard import model
from scoreboard.reports import text
import scoreboard.reports.text as report

print(model.__name__, report.__name__)

A folder with an __init__.py file is a package. Dotted imports, aliases and relative imports such as from .model import Record and from .. import state work. A package's own __init__.py runs before any module inside it, and once a submodule has loaded it appears as an attribute of its package. Not yet supported: packages without an __init__.py (namespace packages), from module import *, imports inside functions or if blocks, and importing Python's standard library.

Circular imports

# fragment: conformance/cases/circular_modules/a.py
import b
value = "a"
def read_b():
    return b.value

When two modules import each other, the second import finds the first module half-finished and uses it as it is, exactly as CPython does. A function like read_b may refer to something defined later, as long as it is only called once both modules have finished loading. Reading a module attribute before it has been assigned is caught by the compiler, which stops with the line and column, instead of surfacing as an AttributeError while the program runs.

The entry point

def main():
    print(__name__, __doc__ is None)

if __name__ == "__main__":
    main()

__name__, __doc__, __package__ and __spec__ are available whenever your code mentions them, and a function's or method's __module__ names the module that defined it. import __main__ gives you the very same namespace as the file you compiled, while importing that file by its own name loads a separate copy, as in Python.

Classes across modules

A class you write can be imported, given another name, passed around and used as the parent of a class in another file. Its name, its module's variables and its methods stay tied to the module that defined it, and isinstance, issubclass and callable work on imported classes. The class_window.py example keeps the model behind its window in an imported class.

Limits

Imports may nest up to 128 deep, and a program may contain up to 32,767 modules. An import form that is not supported, or a module the compiler cannot find, stops the compile with a message at the line and column. __file__, __loader__, __path__ and inspecting modules while the program runs are not yet supported.

What the tests cover

Every claim on this page comes from a test program that runs in both d/Python and CPython and must print the same thing. The corpus page lists those programs, with their reviewed output.