Python Essentials for AI Engineer

Course Content

Python Essentials for AI Engineer

6 sections · 48 lessons

What is __name__ == "__main__"?


The same train.py, two ways inpython train.py• __name__ is "__main__"• Guarded block runs• Training starts• Right for the command lineimport train• __name__ is "train"• Guarded block is skipped• Only definitions load• Safe for notebooks and workers
The guard is about import side effects: without it, reusing one function starts a three-hour training run.

What you need to know

Seeing it work

Python
import pathlib, subprocess, syspathlib.Path("train.py").write_text(    'def build_model():\n'    '    return "model"\n'    'print("__name__ is", __name__)\n'    'if __name__ == "__main__":\n'    '    print("training for 3 hours...")\n',    encoding="utf-8",)print(subprocess.run([sys.executable, "train.py"], capture_output=True, text=True).stdout)# __name__ is __main__# training for 3 hours...print(subprocess.run([sys.executable, "-c", "import train"], capture_output=True, text=True).stdout)# __name__ is train

Run directly, both lines print. Imported, only the unguarded print runs, and the training block is skipped.

The standard shape of a script

Python
import argparsedef main(argv=None):    parser = argparse.ArgumentParser()    parser.add_argument("--epochs", type=int, default=3)    args = parser.parse_args(argv)    return f"training for {args.epochs} epochs"if __name__ == "__main__":    print(main())

Putting the work in main() means tests can call main(["--epochs", "1"]) directly, and nothing runs on import.

Why multiprocessing needs it

With the spawn start method — the default on Windows and macOS — each worker process starts a fresh interpreter and imports your main module to find the function it should run. Since Python 3.14, Linux defaults to forkserver, which also starts from a fresh process. Without the guard, each worker would re-run your top-level code, including starting new workers. Python detects this and raises a RuntimeError about starting a new process "before the current process has finished its bootstrapping phase".

python -m package.module runs a module inside a package as __main__, which is also how relative imports keep working in a script.

A real-life example

A data scientist's train.py contained the training loop at the top level. A colleague wrote from train import build_model in an evaluation notebook to reuse the model definition — and the import started a 3-hour GPU training run, overwriting the saved checkpoint at the end.

Later, the same script used a PyTorch DataLoader(..., num_workers=4) on a MacBook. Every worker re-imported train.py, and the job crashed with the bootstrapping RuntimeError. Both problems had one fix: move the work into main() and call it under if __name__ == "__main__":. Now the file is a safe library for the notebook and a working script for training.

Follow-up questions to expect

  • "What is __name__ when a module is imported?" — The module's name as imported, for example "train" or "rag.chunking".
  • "What does python -m do?" — It finds a module on sys.path and runs it as __main__, keeping package context so relative imports work.
  • "Is the guard required in every file?" — No. Only in files that can be run directly and also have code that should not run on import.