The Weirdest Line in Python — Demystified
Open almost any Python file and you'll eventually see this at the bottom:
if __name__ == "__main__":
main()
It looks like a bit of magical boilerplate. It's actually a very practical feature once you know what it does — and it exists because Python doesn't draw a line between "scripts" and "libraries."
The Setup: Two Ways to Use a File
Every .py file in Python can be used in two different ways:
- As a script — you run it directly with
python3 file.py. - As a module — another file imports it with
import file.
The language doesn't make you declare which one you're writing. Any file might end up doing both.
Consider a file called math_helpers.py:
# math_helpers.py
def mean(values):
return sum(values) / len(values)
def median(values):
s = sorted(values)
mid = len(s) // 2
if len(s) % 2 == 0:
return (s[mid - 1] + s[mid]) / 2
return s[mid]
# Quick smoke test while developing
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
print("mean:", mean(numbers))
print("median:", median(numbers))
If you run this file directly, it prints the test output — great. But if some other file does import math_helpers, those print statements run during the import. Every user of the module sees your dev scratch output. Not great.
What __name__ Is
Every Python module has a built-in variable called __name__. Python sets it automatically:
- When the file is imported,
__name__is set to the module's import name —"math_helpers"in the example above. - When the file is run directly, Python sets
__name__to the special string"__main__".
That gives you a way to tell which mode you're in. Wrap the "script-only" code in a check:
# math_helpers.py
def mean(values):
return sum(values) / len(values)
def median(values):
s = sorted(values)
mid = len(s) // 2
if len(s) % 2 == 0:
return (s[mid - 1] + s[mid]) / 2
return s[mid]
if __name__ == "__main__":
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
print("mean:", mean(numbers))
print("median:", median(numbers))
Now python3 math_helpers.py prints the test output. But import math_helpers from another file skips the block entirely — the functions are available, and nothing unwanted runs.
The Common Companion: a main() Function
Most real scripts grow a dedicated main() function and keep the guard block tiny:
# process_orders.py
import sys
def load_orders(path):
with open(path) as f:
return [line.strip() for line in f if line.strip()]
def process(orders):
for order in orders:
print(f"Processing {order}")
def main():
if len(sys.argv) < 2:
print("Usage: python3 process_orders.py <file>")
sys.exit(1)
orders = load_orders(sys.argv[1])
process(orders)
if __name__ == "__main__":
main()
Why bother with a main() instead of putting the logic directly under the if guard?
- Testability. You can import the module and call
main()(or any of the helpers) from tests. - Local variables. Anything defined inside
main()is a local variable, not a module-level name. That avoids accidental name collisions and makes the module's public surface cleaner. - Readability. The guard block is now two lines — a clear "script entry point" rather than a pile of logic.
A Quick Demonstration
You can see the behavior directly:
When you run the snippet above with Python, it prints __name__ is: __main__ and "being run as a script." If some other file imported this one, the same check would print the other branch.
When You Don't Need the Guard
Plenty of Python files never grow one. Short scripts that nobody would ever import are fine without it:
# one_off_rename.py
import os
for name in os.listdir("."):
if name.endswith(".txt"):
os.rename(name, name.lower())
That's perfectly good. You're not building a library; nobody's going to import this. The moment there's reusable logic in a file, though — and you want to keep side-effect code alongside it — reach for the guard.
Entry Points for Installed Packages
Once you're publishing your code as a real package, there's a more formal mechanism: entry_points in your package metadata, which map a command to a function. Users installing your package get a shell command that calls the function directly. But for scripts running out of a folder on your own machine, the __main__ guard is the standard tool.
Wrapping Up This Chapter
You now have:
- Functions to name your logic.
*args/**kwargsfor flexible calls.- Lambdas for throwaway functions.
- Decorators and type hints to wrap and document those functions.
- Modules, pip, and virtual environments to split code across files and projects.
- The
__main__guard to let scripts and modules coexist.
Next: Classes
You've mostly been pairing functions with plain data — dicts, lists, tuples. The next chapter introduces classes, Python's way of tying data and behavior together, and the place where concepts like self, __init__, inheritance, and dataclasses live.
Frequently Asked Questions
What does if __name__ == '__main__' do?
if __name__ == '__main__' do?It only runs the block below it when the file is executed directly (not when the file is imported as a module). This lets you write a .py file that can either be run as a script or imported for its functions and classes — without the script actions happening during import.
Does Python need a main function?
No. Python files run top-to-bottom automatically. But as soon as a file has logic you want to also be importable, the if __name__ == '__main__' guard becomes important — and putting the script's top-level work inside a main() function is a common companion habit.
What's the difference between __name__ and __main__?
__name__ and __main__?__name__ is a special variable Python sets in every module. If the file is imported, __name__ is the module's name (like 'util'). If the file is run directly, Python sets __name__ to the string '__main__'. The if check compares the two.