How it works
The explanation, with examples you can run.
What import does
import sysimport json print("json" in sys.modules) # Trueimport json as againprint(again is json) # True: the second import is a dict lookupprint(json.__name__, __name__) # json __main__Because a module body runs only once, module-level code acts as one-time setup, and module-level variables act as process-wide singletons. The file you run directly is named "__main__" rather than its file name, which is what the if __name__ == "__main__": guard tests: that code runs when the file is executed as a script but not when it is imported.
A package is a directory of modules, normally with an __init__.py that runs when the package is first imported. from . import models is a relative import inside a package; it only works when the file is imported as part of that package (for example with python -m mypkg.cli), not when run as a loose script.
Imports run in order, and a module is registered in sys.modules before its body finishes. That is why circular imports fail in a confusing way: if a imports b and b immediately uses a.X, b gets the half-initialised a and raises AttributeError: partially initialized module 'a' has no attribute 'X' (most likely due to a circular import).
Where Python looks
The search goes through sys.path in order: the directory of the script (or the current directory for -m and the REPL), then entries from PYTHONPATH, then the standard library, then site-packages, where installed packages live. First match wins. A file called random.py or json.py in your project shadows the standard module, a classic source of baffling errors.
Virtual environments
Each Python installation has one site-packages. A virtual environment is a lightweight directory with its own site-packages and a python that uses it, while sharing the base interpreter's standard library:
python3 -m venv .venv # create it (once per project)source .venv/bin/activate # put .venv/bin first on PATH (Windows: .venv\Scripts\activate)python -m pip install requests # installs into .venv onlyActivation only changes PATH; running .venv/bin/python directly works just as well. Using python -m pip rather than a bare pip guarantees that pip installs into the interpreter you are actually going to run. Many Linux distributions and Homebrew now mark their system Python as externally managed (PEP 668), so pip refuses to install into it outside a venv.
pyproject.toml
Modern projects describe themselves in pyproject.toml. The [project] table (PEP 621) holds the name, version, requires-python and dependencies; [build-system] (PEP 517 and 518) names the backend, such as setuptools, hatchling or flit-core, that turns the source into a wheel, the pre-built archive pip installs. pip install . reads this file, builds a wheel and installs it. Dependency lists in pyproject.toml say what a package can work with; to pin exact versions for an application, use a lock file. Tools such as pip-tools, Poetry, PDM and uv produce them, and PEP 751 defines a standard pylock.toml format.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.