if __name__ == "__main__" in Python: the entry point of a script

The if __name__ guard separates what a Python file must run when it is launched from what it should merely make available when it is imported.
5 min read
Believemy logo

Definition

A Python file can be read in two different ways: run directly from a terminal, or imported by another file that only wants one function from it. The trouble is that Python makes no difference between the two by default, for lack of a mandatory function called main as in C or Java: running a file simply means executing its lines from top to bottom, definitions included.

That is what the if __name__ == "__main__" guard solves. Sitting at the bottom of the file might suggest it starts the program, but it actually separates what must run on launch from what should stay available on import.

PYTHON
def add(a, b):
    return a + b


if __name__ == "__main__":
    print(add(2, 3))  # only runs when the file is launched directly

Run directly, this file prints 5. Imported with import, it prints nothing: it merely offers its function add. The code is identical, only the usage changes.


What __name__ holds in each situation

Before running a file, Python drops a special variable into it, __name__. One might expect it to always hold the same thing; it is the opposite that makes the mechanism useful. Here is what it holds depending on how the file was loaded.

SituationContent of __name__
python tools.py"__main__"
The same file imported elsewhere"tools"
python -m tools"__main__"
Typed straight into the REPL"__main__"
File loaded by pytest"test_tools"

The launched file is always called __main__, every other one keeps its usual module name. The comparison therefore only asks whether this file is being launched or merely loaded.


The problem it actually solves

Without that guard, importing a file runs the whole file, not just its definitions: the calls, the printed output, the file being opened, the network request being sent all come along with them, the day someone imports a script to reuse a single function.

PYTHON
# cleanup.py, no guard
def clean(path):
    ...


clean("data.csv")   # also runs on import, whether that was wanted or not

The costliest case involves multiprocessing. On Windows and on macOS, it cannot duplicate the running process the way Linux does: it restarts each child process by re-importing the main file.

Warning

Without a guard, that re-import restarts the process creation, which itself re-imports the file and creates more processes in turn. The system eventually forces this avalanche to stop, with an error message mentioning freeze_support and never naming the real cause.


The shape to write, and why that one

It is better not to put the whole program inside the guard, but to keep a single call there, one that calls a main function holding the rest.

PYTHON
def main():
    config = load_config()
    process(config)


if __name__ == "__main__":
    main()

The reason comes down to scope. Whatever is written inside the block belongs to the module: every name becomes a global variable, changeable by accident from anywhere in the file. Wrapped inside a function, that same code keeps its names to itself, becomes testable, and attachable to a terminal command, which is exactly the second meaning of the term.


The other meaning: the installed command

The same term covers a second thing, often confused with the first. A published package can declare entry points in its configuration file: each one creates a terminal command that calls one precise function of the project. That is how pip installs commands usable without typing python in front of them.

BASH
pip install ruff
ruff check .

The two notions resemble each other without replacing each other, hence the value in knowing which one is being looked for.

Point of comparisonThe guard in the fileThe project declaration
Where it is writtenAt the bottom of the script concernedIn the configuration file of the package
What it producesA file behaving differently when launched and when importedA command available in the terminal after installation
When it earns its placeAs soon as a file is both a script and a libraryWhen a project has to be used like a real tool


When the guard is useless

It is neither magic nor mandatory. A file of functions never launched directly has nothing to protect. A throwaway ten-line script, written to run once and never imported, does not need it either.

The classic mistake is copying it everywhere without knowing why. The mirror mistake is forgetting it when it matters: a file that grows, that a colleague eventually imports, or that a test suite loads to check a single function. The right reflex is to ask, once per file, whether anyone could ever import it.


Frequently asked questions

Question

Is a main.py file required as in other languages?

No, the file name means little to Python: whichever file is passed to the command becomes the entry point, whatever it happens to be called. The one exception is the __main__.py file placed inside a package folder, which makes that folder runnable with python -m mypackage and acts as the official door of the project.

Question

Why does my script seem to run twice?

Because the same file is loaded under two identities: once as the launched file, under the name __main__, and once as an imported module, under its real name. Python then keeps two separate copies in memory, with two independent sets of global variables. The guard is not always enough: a launched file must also avoid ending up importing itself.

Question

What happens when the quotes or the underscores are written wrong?

Nothing visible, which is exactly what makes the mistake expensive. Writing if __name__ == "main" produces a valid comparison that is always false: the block never runs, and no error is printed. A typo on the variable itself is louder, since an unknown name raises a NameError. So count two underscores on each side of the word, and check the exact word sitting between the quotes.

Related terms

Discover our python glossary

Browse the terms and definitions most commonly used in development with Python.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.