Report this

What is the reason for this report?

How to Use the Python Main Function

Updated on March 19, 2026
How to Use the Python Main Function

The Python main function is the conventional entry point for a script: you define a function (typically named main) that holds your program logic and call it only when the file is run directly, not when it is imported as a module. Python does not call main() automatically; the pattern if __name__ == "__main__": is what lets you separate “run as script” from “import as module.” When the file is executed directly, the interpreter sets the special __name__ variable to "__main__", so the block under that condition runs and can call main(). When the file is imported, __name__ is set to the module name, so that block is skipped and your module can be reused without side effects. This article shows how to define and use the Python main function, how CPython assigns __name__, how to make packages runnable with __main__.py, how to integrate argparse, and how to structure scripts for testability and correct exit codes.

Key Takeaways

  • The Python main function is not special to the interpreter; you define it yourself and call it from a if __name__ == "__main__": block so it runs only when the file is executed directly.
  • CPython sets __name__ to "__main__" when you run a file with python file.py, and to the module name (filename without .py) when the file is imported, which is how the guard works.
  • Use a def main() function to hold your script logic and call it from the if __name__ == "__main__": block; use sys.exit(main()) so the process returns a proper exit code to the shell.
  • For packages, add a __main__.py in the package directory so python -m packagename runs that file as the Python entry point.
  • The if __name__ == "__main__": guard keeps top-level code from running on import, which makes scripts testable and avoids side effects when the file is used as a module.

What Is the Python Main Function?

In Python there is no built-in “main” that the interpreter runs. The Python main function is a convention: you define a function (usually named main) that contains your script’s logic and invoke it only when the file is run as the main program. This gives you a clear Python entry point and keeps the file usable as a module.

Without a guard, every top-level statement in a file runs both when you execute the file and when you import it. That leads to unwanted side effects when the file is used as a module. The standard approach is to put the call to your main function inside if __name__ == "__main__":, so the Python script execution flow runs your entry point only when the file is executed directly, not when it is imported.

The following example shows the pattern. Top-level print runs in both cases; the call to main() runs only when the file is executed directly.

print("Module loading: top-level code runs on import and on direct run")

def main():
    print("python main function: entry point when run directly")

if __name__ == "__main__":
    main()

When you run this file directly:

Module loading: top-level code runs on import and on direct run
python main function: entry point when run directly

When you import it from another script, you will see only the first line; the block under if __name__ == "__main__": does not run, so the difference between Python module vs script execution is clear.

Understanding the name Variable in Python

The __name__ global variable Python sets for every module is the key to the main-guard pattern. It is a string that identifies how the current file is being used: as the main program or as an imported module.

How CPython Assigns name

When CPython runs a file, it sets __name__ in a few common ways:

  1. Direct execution: You run python myfile.py. CPython sets __name__ to the string "__main__" for that file. So the file is treated as the Python main module.
  2. Import: Another module imports it (for example, import myfile or import pkg.myfile). CPython loads the module and sets __name__ to its import name: "myfile" in the first case and "pkg.myfile" in the second.
  3. Module as a script via -m: You run python -m some_module (or python -m pkg.myfile). Python finds that module and executes it as a script, setting __name__ to "__main__" inside that module.

So the same file can behave as either the main program or a library depending on Python import vs direct execution. The following example demonstrates both paths with annotated output.

File: greet.py

print("greet.py is executing. __name__ =", repr(__name__))

def main():
    print("Hello from main()")

if __name__ == "__main__":
    main()
    print("(Direct run: __name__ was __main__, so this block ran)")
else:
    print("(Imported: __name__ was", repr(__name__) + ", so main() was not called)")

Run directly: python greet.py

greet.py is executing. __name__ = '__main__'
Hello from main()
(Direct run: __name__ was __main__, so this block ran)

Import from another script: python -c "import greet"

greet.py is executing. __name__ = 'greet'
(Imported: __name__ was 'greet', so main() was not called)

So: when run directly, __name__ is "__main__" and main() runs; when imported, __name__ is the module name and the main block is skipped. That is the internal mechanism behind the Python main function pattern. Python interpreter execution order is always top to bottom; the only difference is the value of __name__ when your code runs.

Using if name == “main” in Python

The condition if __name__ == "__main__": is the standard way to mark the block that should run only when the file is the main program. It implements the Python reusable script pattern: the same file can be both a script and an importable module.

Anything inside that block is Python top-level code that runs only on direct execution. Typically you call a main() function there so all script logic lives in one place. If you omit the guard, every top-level statement runs on import too, which can cause side effects (prints, network calls, file writes) when the file is used as a module.

The next section ties this to testability: the guard is what lets test runners import your script without running its entry point.

Defining a def main() Function in Python

You can name your entry-point function anything, but the convention is main. Defining a def main() Python function and calling it from the if __name__ == "__main__": block keeps script logic in one place and makes the entry point obvious.

Define main() before the guard so it exists when the block runs. If the guard appears above the function definition, you will get NameError: name 'main' is not defined when the file is run directly.

Example:

import sys

def main():
    print("Running main logic")
    return 0

if __name__ == "__main__":
    sys.exit(main())

Running the file directly produces:

Running main logic

Using a single main() function is the standard Python best practices script structure for small scripts and CLI tools.

Making a Python Package Executable With main.py

A Python package (a directory containing an __init__.py) can be run as a script by adding a __main__.py file inside that directory. When you run python -m packagename, the interpreter looks for packagename/__main__.py and executes it as the Python entry point. This is how many CLI tools packaged as directories are invoked (e.g. python -m pip, python -m http.server).

Minimal layout:

mytool/
    __init__.py
    __main__.py

mytool/__init__.py (can be empty):

# Package marker; can be empty

mytool/__main__.py:

import sys

def main():
    print("Running mytool as a package")
    return 0

sys.exit(main())

Note: __main__.py is executed directly by the interpreter when you run python -m mytool, so __name__ is always "__main__" in that file. You do not need an if __name__ == "__main__": guard here unless you also intend to import __main__.py as a module, which is uncommon.

From the directory that contains mytool, run:

python -m mytool
Running mytool as a package

Python invokes mytool/__main__.py when you use python -m mytool.

Note: The parent directory containing mytool must be on sys.path (e.g. run from that directory or install the package). For more on package layout, see How to Make a Python Package.

Integrating argparse With Your Python Main Function

You can wire argparse into your Python main function by defining the parser and parsing in the if __name__ == "__main__": block, then passing the parsed namespace into main(). That keeps argument parsing at the entry point and leaves main() testable with plain values.

Example: argument definition, parsing, and passing parsed args through main().

import argparse
import sys

def main(args):
    greeting = f"Hello, {args.name}!"
    if args.loud:
        greeting = greeting.upper()
    print(greeting)
    return 0

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Echo a greeting")
    parser.add_argument("--name", default="World", help="Name to greet")
    parser.add_argument("--loud", action="store_true", help="Uppercase the greeting")
    parsed = parser.parse_args()
    sys.exit(main(parsed))

Help output: python script.py --help

usage: script.py [-h] [--name NAME] [--loud]

Echo a greeting

options:
  -h, --help    show this help message and exit
  --name NAME   Name to greet (default: World)
  --loud        Uppercase the greeting

Sample run: python script.py --name "DigitalOcean" --loud

HELLO, DIGITALOCEAN!

For more patterns, see How to Use argparse to Write Command-Line Programs in Python. For defining the functions that use those arguments, see How to Define Functions in Python 3.

Using the name Guard for Testability

The if __name__ == "__main__": guard prevents import-time side effects. When a test suite (e.g. pytest or unittest) imports your script to test its functions, only the module-level code outside the guard runs; the main block does not. So you avoid running the whole program just because you imported it.

Without the guard: script runs its logic on import, which is bad for tests.

# script_without_guard.py
def main():
    print("Doing work")

# BAD: runs on import
main()

When a test file does import script_without_guard, it will see “Doing work” printed and any side effects of main() will run. That makes tests noisy and can change global state.

With the guard: script imports cleanly; entry point runs only when executed.

# script_with_guard.py
def main():
    print("Doing work")

if __name__ == "__main__":
    main()

When a test file does import script_with_guard, only the function definition is loaded; nothing is printed and no side effects run. Tests can call script_with_guard.main() when they need to. So the guard is what makes the script both runnable and safely importable for testing.

Why Use sys.exit() in a Python Main Function

Processes report success or failure to the shell via exit codes: 0 usually means success, non-zero means an error. In Python, the process exit code is set by sys.exit(code). If you do not call it, the interpreter exits with 0 when main() returns or when the script finishes, even when your logic detected an error. Using sys.exit(main()) ties the process exit code to the return value of your Python main function.

Have main() return 0 on success and a non-zero integer on failure, then pass that to sys.exit():

import sys

def main():
    # Simulate a failure check
    if len(sys.argv) > 1 and sys.argv[1] == "--fail":
        return 1
    print("Success")
    return 0

if __name__ == "__main__":
    sys.exit(main())

When run without --fail, the script prints “Success” and exits with code 0. When run with --fail, it returns 1 and prints nothing. The shell sees that code (e.g. echo $? prints 0 or 1 after the script runs).

python script.py
Success
echo $?
0
python script.py --fail
echo $?
1

Warning: If main() does not return an integer, sys.exit(main()) may not behave as intended. sys.exit() expects an integer or an object with a compatible meaning; for clarity, have main() explicitly return 0 or a non-zero int.

So for any script that can fail, the sys.exit(main()) pattern is the right approach.

Python Main Function Best Practices

  1. Use the guard for the entry point. Always put the call to your main logic inside if __name__ == "__main__": so the file can be imported without running that logic. This is the standard Python reusable script pattern.

  2. Name the entry-point function main(). You can use another name, but def main() Python convention makes the entry point obvious to other developers and to tools.

  3. Return an exit code from main() and use sys.exit(main()). Have main() return 0 on success and a non-zero integer on failure, and call sys.exit(main()) in the guard block so the process reports the correct exit code to the shell.

  4. Keep argument parsing at the boundary. Parse argparse (or other CLI args) in the if __name__ == "__main__": block or at the start of main(), and pass parsed values into the rest of your code. That keeps main() testable with plain arguments.

  5. Avoid side effects at top level. Put only imports, constants, and function/class definitions at module level. Do not run heavy logic or I/O at top level; do it inside main() or behind the guard so imports stay fast and side-effect free.

  6. For runnable packages, use __main__.py. If your project is a package, add __main__.py and implement the entry point there so users can run it with python -m packagename.

Following these rules keeps your Python script execution flow clear, makes scripts testable and reusable as modules, and aligns with common Python best practices for script structure.

Frequently Asked Questions

What does if name == “main” mean in Python?

It means: run the following block only when this file is executed as the main program, not when it is imported as a module. When you run the file with python file.py, Python sets __name__ to "__main__", so the condition is true and the block runs. When the file is imported, __name__ is the module name, so the condition is false and the block is skipped.

What does the main() function do in Python?

The main() function is the conventional place for your script’s logic. Python does not call it automatically; you define it and call it from the if __name__ == "__main__": block. It gives you a single, clear entry point and keeps the file importable without running that logic.

Is if name == “main” necessary in Python?

It is not required by the language, but it is the standard way to separate “run as script” from “import as module.” Without it, every top-level statement runs on import too, which causes side effects and makes the file hard to test and reuse. For any file that is both run directly and imported, the guard is the recommended pattern.

What is the equivalent of the main() function in Python?

Python has no built-in main. The equivalent is to define your own function (usually main) and call it from if __name__ == "__main__":. That block is the Python entry point when the file is run directly.

What is the name variable in Python?

__name__ is a special string set by the interpreter for every module. When a file is run directly with python file.py, __name__ is "__main__". When the file is imported, __name__ is the module name (the filename without .py). The __name__ global variable Python uses is what makes the main-guard pattern work.

What is main.py used for in Python?

__main__.py is used to make a package runnable with python -m packagename. It lives inside the package directory. When you run python -m packagename, the interpreter executes packagename/__main__.py as the entry point. Many CLI tools use this so the package can be invoked as a script.

How do I pass command-line arguments to a Python main function?

Parse arguments with argparse (or another parser) at the entry point, then pass the parsed result into main(). For example: in the if __name__ == "__main__": block (or at the start of main()), call parser.parse_args() to get a namespace, then pass that namespace or its attributes into main(args) or use them inside main(). That keeps parsing at the boundary and leaves main() testable with plain values.

Why should I use sys.exit() in a Python main function?

So the process reports the correct exit code to the shell (0 for success, non-zero for failure). Have main() return that code and call sys.exit(main()) in the guard block. If you do not call sys.exit(), the process may always exit with 0 even when your logic failed, which breaks scripts and automation that rely on exit codes.

Conclusion

The Python main function pattern—using if __name__ == "__main__": and placing the main logic in a main() function—is a best practice for writing clean, reusable, and testable Python scripts. This approach allows your code to behave correctly whether it is run as a script or imported as a module, avoids top-level side effects, and enables powerful features like __main__.py for packages. By following these conventions and structuring your scripts thoughtfully, you make your Python projects easier to maintain, extend, and incorporate into larger applications or workflows.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the author(s)

Pankaj Kumar
Pankaj Kumar
Author
See author profile

Java and Python Developer for 20+ years, Open Source Enthusiast, Founder of https://www.askpython.com/, https://www.linuxfordevices.com/, and JournalDev.com (acquired by DigitalOcean). Passionate about writing technical articles and sharing knowledge with others. Love Java, Python, Unix and related technologies. Follow my X @PankajWebDev

Vinayak Baranwal
Vinayak Baranwal
Editor
Technical Writer II
See author profile

Building future-ready infrastructure with Linux, Cloud, and DevOps. Full Stack Developer & System Administrator. Technical Writer @ DigitalOcean | GitHub Contributor | Passionate about Docker, PostgreSQL, and Open Source | Exploring NLP & AI-TensorFlow | Nailed over 50+ deployments across production environments.

Category:
Tags:

Still looking for an answer?

Was this helpful?

The best site with the best information I’ve ever found! Thousands of thanks!

- Sensation Person

Well Done Pankaj, very well explained. So far this is the best one from desi !!!

- Srinivas

Very good explanation , keep it up

- Hari Haran

Very well explained .

- RandomGoogler

Nice document. It will be helpful for a lot of beginners. Thanks

- Kiran

Still relevant. Thanks for the simple but elegant breakdown. I needed that and truly appreciate it.

- Eric Webb

Thanks so much for this breakdown. It was super clear and helpful for a begginer like myself.

- Nahuel Tamasso

Creative CommonsThis work is licensed under a Creative Commons Attribution-NonCommercial- ShareAlike 4.0 International License.
Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.