Filter concepts by levelShowing all levels.

Python · Fundamentals

Modules and imports

How a file becomes a namespace, how packages nest, and where import actually looks

  • A module is one fileimport runs it once, then caches the result
  • A package is a directoryneeds __init__.py to be importable
  • __name__ == "__main__"true only on direct execution, never on import
  • sys.path, in orderscript directory, then PYTHONPATH, stdlib, site-packages

1.Modules

A module is just a `.py` file. `import mathy` runs mathy.py once and binds the name `mathy` to the resulting namespace object, so every name mathy.py defined is reachable as mathy.something.

Key features

  • Any file ending in .py is automatically a module — nothing marks it as one
  • import name runs name.py once and binds name to the resulting module object
  • Access what the file defined as name.thing — an attribute lookup, not a copy
  • import name as alias binds a shorter or non-clashing name to the same module
  • from name import thing binds thing directly, skipping the name. prefix

Ways to bring a module — or a name from it — into scope

Ways to bring a module — or a name from it — into scope
FormWhat it binds
import mathymathy — access everything as mathy.thing
import mathy as mm — same module object, shorter name
from mathy import areaarea directly — no mathy. prefix needed
from mathy import area as circle_areacircle_area — renamed on the way in
A file becomes a namespace on import

mathy.py

PI = 3.14159, def area(r): ...

import mathy

the file runs, top to bottom, once

mathy

a namespace: mathy.PI, mathy.area

  1. mathy.py — PI = 3.14159, def area(r): ...
  2. import mathy — the file runs, top to bottom, once
  3. mathy — a namespace: mathy.PI, mathy.area

Command

python
import mathy                        # bind the module itself
import mathy as m                   # bind it under a shorter name
from mathy import area              # bind one name directly
from mathy import area as circle_area  # bind it, renamed

import runs a .py file once and hands back a namespace object — mathy.thing reaches into it; from mathy import thing skips the prefix.

2.Absolute and relative imports

An absolute import spells the full path from the top-level package. A relative import uses leading dots instead, counted from the current module, and only works inside a package.

Key features

  • Absolute: from shop.pricing import apply_discount — the full path, always
  • Relative: from .pricing import apply_discount — one dot means "this package"
  • Two dots (from ..utils import x) means "the parent package", and so on
  • Relative imports only work when the module is imported AS PART OF a package
  • Running a file directly (python file.py) makes its relative imports fail

Absolute vs. relative, from inside shop/checkout.py

Absolute vs. relative, from inside shop/checkout.py
FormMeaning
from shop.pricing import apply_discountabsolute — full path from the top package
from .pricing import apply_discountrelative — pricing.py, same directory
from .utils.formatting import as_currencyrelative — one level down, same package
from . import pricingrelative — import the sibling module itself
Same target, two ways to name it

shop.pricing

absolute — full path, from anywhere

same file

shop/pricing.py

.pricing

relative — one dot, from checkout.py's position

  1. shop.pricing — absolute — full path, from anywhere
  2. same file — shop/pricing.py
  3. .pricing — relative — one dot, from checkout.py's position

Command

python
from shop.pricing import apply_discount    # absolute — from the top-level package
from .pricing import apply_discount        # relative — same directory as this file
from ..other_package import thing          # relative — one level UP from this file

Absolute spells the full path and works anywhere; relative uses dots from the current file and only works inside a package.

3.__name__ and the __main__ guard

Every module has a __name__ attribute: "__main__" if run directly, or the module's own name if imported. if __name__ == "__main__": guards code so it only runs on direct execution.

Key features

  • Running python file.py sets that module's __name__ to the string "__main__"
  • Importing the same file sets __name__ to the module's own name instead — never "__main__"
  • if __name__ == "__main__": guards code so it runs on direct execution only
  • Without the guard, importing a script re-runs its top-level code — prints and all
  • The idiom lets one file work both as a runnable script and as an importable module

__name__'s value depending on how a file is reached

__name__'s value depending on how a file is reached
How greet.py is rungreet.py's __name__
python greet.py'__main__'
import greet'greet'
python -m shop (running shop/__main__.py)'__main__'
Same file, two ways in, two badges

python greet.py

run directly

__name__

"__main__" here, "greet" if imported

if __name__ == "__main__":

only opens for the direct-run badge

  1. python greet.py — run directly
  2. __name__ — "__main__" here, "greet" if imported
  3. if __name__ == "__main__": — only opens for the direct-run badge

Command

python
if __name__ == "__main__":
    main()   # only runs when this file is executed directly, never on import

__name__ is "__main__" only when a file is run directly; if __name__ == "__main__": guards code so it never fires on import.

4.Packages

A package is a directory that Python can import as a single name, because it contains an __init__.py file. Its submodules are reached with dotted paths — shop.pricing, shop.utils.formatting — mirroring the folder structure on disk.

Key features

  • A package is a directory containing __init__.py, importable as one name
  • Submodules are reached by dotted path: shop.pricing, shop.utils.formatting
  • A package can nest — shop/utils/ is a package inside the shop package
  • __init__.py can be empty; it only has to exist for the directory to count
  • Code placed in __init__.py runs once, the first time the package is imported

A small package layout and how each piece is reached

A small package layout and how each piece is reached
Path on diskReached as
shop/__init__.pyimport shop
shop/pricing.pyimport shop.pricing, or shop.pricing.apply_discount
shop/utils/__init__.pyimport shop.utils
shop/utils/formatting.pyimport shop.utils.formatting
A directory becomes a dotted namespace

shop/

__init__.py

pricing.py

shop/utils/

formatting.py

  • shop/ — has __init__.py — a package
    • __init__.py
    • pricing.py
  • shop/utils/ — nested package, one level down
    • formatting.py

Command

python
import shop.pricing                       # dotted path all the way down
from shop.pricing import apply_discount   # skip straight to a name inside it
from shop.utils.formatting import as_currency

A package is a directory with __init__.py; its submodules follow the folder structure exactly, one dot per level.

5.Import resolution and caching

import name searches sys.path in order and stops at the first match. Once found, the module is cached in sys.modules, so a second import reuses the same object instead of running the file again.

Key features

  • sys.path is a list of directories, checked in order, first match wins
  • sys.path[0] is the running script's own directory — checked before everything else
  • After that: PYTHONPATH, the standard library, then installed site-packages
  • sys.modules caches every module already imported, keyed by its full name
  • A second import of an already-cached module reuses it — the file body does not run again

sys.path's search order, top to bottom

sys.path's search order, top to bottom
PositionWhat it holds
sys.path[0]the running script's own directory (or '' for -c/interactive)
PYTHONPATH entriesdirectories from that environment variable, if set
standard libraryjson, os, sys — Python's own bundled modules
site-packagesanything installed with pip

Command

python
import sys
sys.path[0]          # the running script's own directory — checked first
sys.modules           # dict of {module name: module object}, the import cache

sys.path is searched in order (script directory first); sys.modules caches every result, so a module only ever runs once per process.

6.__init__.py

__init__.py marks a directory as a package and runs once, on first import. It can be empty, or re-export names from submodules so a caller reaches them through the package name directly.

Key features

  • A directory needs __init__.py to be importable as a package — even if empty
  • __init__.py's code runs once, the first time the package is imported
  • from .pricing import x inside __init__.py re-exports x on the package itself
  • __all__ = [...] in __init__.py controls what from package import * pulls in
  • A namespace package (no __init__.py) exists but behaves differently — an edge case

What __init__.py's content changes for a caller

What __init__.py's content changes for a caller
shop/__init__.py containsHow a caller reaches apply_discount
(empty)from shop.pricing import apply_discount — must name the submodule
from .pricing import apply_discountfrom shop import apply_discount — re-exported directly

Command

python
# shop/__init__.py
from .pricing import apply_discount   # re-export a name from a submodule

__all__ = ["apply_discount"]          # what "from shop import *" actually pulls in

__init__.py marks a directory as a package and runs once on first import — re-export a submodule's name there to make it reachable without the submodule prefix.

7.Circular imports

A circular import is when module A imports B while B imports A back. Python leaves a partially finished module in sys.modules mid-cycle — from x import name can fail there, while import x plus a later x.name usually survives.

Key features

  • A imports B, B imports A (directly or through a longer chain) — that is the whole shape
  • The second half of the cycle sees a PARTIALLY initialized module, not a finished one
  • from x import name fails if name is not yet assigned when that line runs
  • import x (without from) usually survives — the attribute is looked up later
  • The real fix: move the shared piece both modules need to a third module

Two ways to import across a cycle, and what each does at import time

Two ways to import across a cycle, and what each does at import time
FormBehavior in a cycle
from b import func_b (at module level)fails — func_b may not exist yet on the partial module
import b, then b.func_b() (inside a function)works — the lookup happens later, after both modules finish
import inside the function body, not at module topworks — defers the whole import past the cycle

Command

python
import a          # module-style import — survives most cycles
a.func_a()         # attribute looked up later, not at import time

from a import func_a   # name-style import — fails if func_a isn't defined yet

A circular import survives if the cross-reference is looked up later (import x, then x.name) — it fails immediately with from x import name.

8.sys.path

sys.path is a plain list of directory strings that import searches in order, stopping at the first match. It is an ordinary list, so code can read it or append to it at runtime.

Key features

  • sys.path is a plain Python list of directory-path strings, built at interpreter startup
  • sys.path[0] is the running script's own directory (or '' for -c and interactive mode)
  • PYTHONPATH (an environment variable) contributes additional directories, if set
  • sys.path.append(path) or sys.path.insert(0, path) adds a directory at runtime
  • import searches sys.path top to bottom and stops at the first matching module name

Common sys.path operations

Common sys.path operations
CallEffect
sys.paththe current list of searched directories, in order
sys.path[0]the running script's own directory
sys.path.append(path)adds path at the END — checked last
sys.path.insert(0, path)adds path at the START — checked first, can shadow stdlib

Command

python
import sys
sys.path                       # the current search list, top to bottom
sys.path.append('/some/dir')   # search there too, checked LAST
sys.path.insert(0, '/some/dir')  # search there FIRST, ahead of everything else

sys.path is a mutable list import searches in order — the script's directory comes first, and code can append to it at runtime.

Remember

  • import runs a file once and caches it in sys.modules — a second import reuses the same object, never re-runs the file.
  • __name__ is "__main__" only on direct execution; guard script-only code with if __name__ == "__main__":.
  • A directory needs __init__.py to be importable as a package, even if the file is empty.
  • A circular import usually survives as import x (looked up later) but fails as from x import name (needed immediately).

Pro tip

  • Relative imports (from .pricing import x) only work inside a package — run the package with python -m, never the file directly.
  • sys.path[0] is the running script's own directory, checked before the standard library — never name a local file the same as a stdlib module.
  • Break a circular import by moving the shared piece both modules need into a third module, rather than routing around it.
  • sys.path.append(dir) is checked last; sys.path.insert(0, dir) is checked first and can shadow the standard library.

Next up

  • Object-Oriented Python
  • Dunder methods
  • Iterators and generators

Sources

  • The import system — docs.python.org/3/reference/import.html
  • Modules — docs.python.org/3/tutorial/modules.html
  • Every example executed on Python 3.14.3 · checked 2026-08-20

Spotted a mistake on this page? Tell us.