Once a project grows past a few files, modules are grouped into packages, which are directories of modules, and packages can contain subpackages. To reach an object deep inside that tree you use a dotted path that mirrors the directory structure. For a file extra/good/best/sigma.py that defines a function funS(), the fully qualified name is extra.good.best.sigma.funS. Each dot steps one level down: package, subpackage, sub-subpackage, module, and finally the object inside the module.
How much of that path you must type depends on how you imported. With import extra.good.best.sigma, Python binds only the top-level name extra in your namespace, and you must always write the full path: extra.good.best.sigma.funS(). This surprises people, but it is consistent: the import statement guarantees that every package along the path is loaded and attached as an attribute of its parent, so the chain of attribute lookups works starting from extra.
Aliasing shortens it: import extra.good.best.sigma as sig binds sig directly to the module, so you call sig.funS(). The from form lets you stop at any level. from extra.good.best import sigma binds sigma, so you write sigma.funS(); from extra.good.best.sigma import funS binds the function itself, so you write funS(). Note that in the plain import a.b.c form the last item must be a module or package, not a function; import extra.good.best.sigma.funS fails with ModuleNotFoundError because funS is not a module.
# Directory tree (each package directory has __init__.py):
# extra/
# good/
# best/
# sigma.py -> def funS(): return 'sigma'
import extra.good.best.sigma
print(extra.good.best.sigma.funS())
from extra.good.best.sigma import funS
print(funS())
import extra.good.best.sigma as sig
print(sig.funS())
For this to work, the top-level directory, here extra, must be findable: it has to sit inside one of the folders listed in sys.path, such as the folder containing your main script. You do not add the inner folders to sys.path; Python walks down the tree using the dotted name. Traditionally each directory contains an __init__.py file marking it as a regular package, and that file runs when the package is first imported.
A useful habit when reading exam code is to write down the directory tree first, then check that each dotted name matches it exactly, including spelling and which level contains the function. Many wrong answers use a path that skips a level or puts the function name where a module should be.
Key terms
- Package
- A directory of modules (and possibly subpackages) that Python can import by name.
- Subpackage
- A package nested inside another package, reached with a dot, such as extra.good.
- Fully qualified name
- The complete dotted path from the top package to an object, such as extra.good.best.sigma.funS.
A team's code lives in company/reports/pdf/render.py. A new script that writes import company.reports.pdf.render must call company.reports.pdf.render.build(); switching to from company.reports.pdf import render lets it call render.build() instead.
Check yourself
After import extra.good.best.sigma, which name is added to your namespace?
Only extra; you reach the function through the full path extra.good.best.sigma.funS().
What must be true about sys.path for import extra.good.best.sigma to work?
The directory that contains the top-level extra folder must be on sys.path; the inner folders do not need to be listed.