What does the if __name__ == "__main__": guard at the end of a Python file do?
answer
- Depends on how the file was started
- Every module has a name global
- Only one module per process is renamed
- Separates definitions from startup work
basics
~20 sPython sets the module global name to "main" only in the file the interpreter was started with; an imported module gets its dotted import name instead. The guarded block therefore runs on direct execution and is skipped on import.
solid answer
~50 sEvery module has a global `__name__`. The import machinery sets it to the module's dotted import name, such as `catalogue.loader`, but whatever the interpreter is *started* with — `python loader.py`, `python -m catalogue.loader`, or a directory or zip path — is executed under the name `__main__`. So `if __name__ == "__main__":` is an ordinary string comparison that is true in exactly one module per process: the entry module. Put startup work inside it — argument parsing, `sys.exit(main())` — and leave the module body to definitions. Without the guard, importing the file for a test run or a documentation tool re-runs that startup as a side effect. The guard is also required around `multiprocessing` work in the main module, because children started with the spawn or forkserver methods re-import the main module and would otherwise launch more children.
code
python · 8 linesdef catalogue_id(record_number):
return f"MUS-{record_number:05d}"
if __name__ == "__main__":
print("started directly:", catalogue_id(83))
else:
print("imported under the name", __name__)go deeper
Be ready to state in one sentence that name equals "main" only in the file you launched, and to write the two-line idiom that calls main() under the guard.
Explain who sets the name: the import machinery for an imported module, the launcher for the entry file. Note that a script path, -m and a directory path all produce main.
Show the production consequence. Unguarded module-level startup runs again whenever a test collector imports the file or a worker process re-imports the main module, so keep entry modules to wiring only.
Own the convention across the codebase: entry points hold wiring, importable modules have no import-time side effects, so any module can be imported by tooling or a worker without booting the application.
### What `__name__` actually is Every Python module has a global named `__name__`, and its value is a plain string. Nothing about it is magic: it is set once, when the module body is executed, by whatever executed it. * When the **import machinery** executes a module, it sets `__name__` to the module's dotted import name — `catalogue`, `catalogue.loader`, `json.tool`. * When the **interpreter starts your program**, it executes that one module under the name `__main__`, whatever the file is called and however you pointed at it. So `__name__ == "__main__"` is a plain string comparison that is true in exactly one module per process: the one the interpreter was launched with. Everything else the guard does follows from that single fact. ### The launch forms all produce the same name All of these execute the target under the name `__main__`: ```console $ python loader.py # a script path $ python -m catalogue.loader # a module found on sys.path $ python catalogue_app/ # a directory containing __main__.py $ python catalogue_app.pyz # a zip containing __main__.py ``` They differ in what becomes importable and in what `__package__` is set to, but not in `__name__`. That is why the guard is written once and works for every launch style. ### What the guard buys you A Python module body is *executable code*, not a declaration block. When you import a module, its top level runs top to bottom: `def` and `class` statements bind names, but a bare `argparse.ArgumentParser(...).parse_args()`, an opened database connection or a `logging.basicConfig()` call runs too. The guard is the line that separates *definitions*, which should happen on every import, from *startup*, which should happen only when this file is the program. The conventional shape is: ```python import sys def main(argv=None): ... return 0 if __name__ == "__main__": sys.exit(main()) ``` `main()` is an ordinary, importable, testable function; `sys.exit(main())` turns its return value into the process exit status. A test can `from catalogue.loader import main` and call it directly with a fabricated argument list without launching anything. ### What goes wrong without it Anything that imports the module pays for the missing guard: * A test collector imports every module it discovers. An unguarded module that parses `sys.argv` at import time will either consume the test runner's own arguments or exit the process outright. * Documentation tools, type checkers with plugins, and any code that resolves a callable from a string all import modules for their side effects. An unguarded module runs its whole program during that import. * Anything that re-imports your entry module — notably worker processes created by `multiprocessing` with the spawn or forkserver start methods — re-executes the module body in the child. Without a guard, the child's re-execution launches more children, and CPython detects this and raises `RuntimeError` with a message about starting a process "before the current process has finished its bootstrapping phase", pointing you at the guard. That last case is the one people meet in production. On Unix platforms other than macOS the default start method changed to forkserver in **3.14** (macOS and Windows use spawn), and both of those re-import the main module in the child, so a script that only ever ran under fork on Linux now needs the guard it never needed before. ### Things the guard is not It does not stop the module body from running on import — only the indented block under it is skipped. It does not make a file importable, and it is not required in library modules that are never executed directly (harmless there, but noise). It does not create a separate namespace: the guarded block runs in the same module globals as everything else, so names it binds become module globals of `__main__`. One more consequence worth knowing: because the entry file is executed under the name `__main__`, its `sys.modules` entry is `"__main__"`, **not** its import name. If some other module also imports that same file by its dotted name, the file runs a second time and you get two independent copies of its globals. The usual defence is the same discipline the guard encourages: keep the entry module thin — parse arguments, call into the package, and hold no state of its own. ### How to answer it in an interview State the rule in one sentence ("`__name__` is `"__main__"` only in the file the interpreter started with"), show the `main()` idiom, and then give one concrete consequence — a test collector importing your module, or a worker process re-importing it. The one-sentence rule alone is the junior answer; the consequence is what makes it a middle one.
- Why is sys.exit(main()) the usual thing to write inside the guard rather than just main()?It keeps `main()` an ordinary importable function that returns a status code, and lets the guard translate that return value into the process exit status. Tests can call `main([...])` directly and assert on the returned code without the process exiting, while the command line still gets a correct exit status for shell scripts and CI to check.
- What actually breaks if a module parses sys.argv at module level instead of inside the guard?Anything that imports the module inherits that parse. A test collector importing the file hands it the test runner's own arguments, so the parser either errors or exits the process during collection. The same happens to documentation tools and to any code that imports the module to resolve a callable. Argument parsing is startup work, and startup work belongs under the guard.
- Does the guard have any effect in a module that is only ever imported?No. Such a module's `__name__` is always its dotted import name, so the comparison is never true and the block never runs. It is harmless there, but it is noise: the guard earns its place in a module that is genuinely used as an entry point, or in one that may be re-executed by worker processes.
It is the difference between a recipe card and actually cooking: importing the file reads the recipe, and only the guard says "and if you are the one at the stove, cook it now".
saying these in an interview costs you the question
- Claims every Python file needs the guard
- Thinks __name__ holds the filename or file path
- Says the guard stops the whole module running on import
- Believes importing a module is what sets __name__ to __main__
- Cannot say why a test collector cares about the guard