runtime
109 / 250
lesson 109 Modules & Packages · intermediate

Library and script: the __main__ guard

`__name__` is `"__main__"` in the file you run and the module's name when it's imported. The guard `if __name__ == "__main__":` keeps a file's script part from running when another program imports it.

You'll be able to
  • Say what __name__ holds when a file is run and when it's imported
  • Put a file's script code (demo calls, printing, reading files) in a main() behind the guard
  • Keep imports free of side effects: no printing, no file reading, no slow work at module level
The idea

Every module has a name in __name__. When a file is imported, it's the module's name ("report_tool"). When a file is the program you ran (python report_tool.py), Python sets it to "__main__".

That difference is how one file can be both a library and a script. Definitions go at the top, as usual. The script part, the code that reads files, prints a report or runs a demo, goes in a main() function, called only under if __name__ == "__main__":. Run the file and the report appears; import it and you just get the functions.

Run each example to see what it prints. Running examples doesn't count toward progress.

example-1.py · Imported, then run as the main program
from pathlib import Path
import importlib
import runpy

Path("report_tool.py").write_text('''def summarize(totals):
    return f"{len(totals)} orders, {sum(totals):.2f} total"

def main():
    print("report:", summarize([12.93, 71.14, 142.77]))

print("__name__ is", __name__)
if __name__ == "__main__":
    main()
''', encoding="utf-8")
importlib.invalidate_caches()

import report_tool
print(report_tool.summarize([5, 7.5]))
runpy.run_path("report_tool.py", run_name="__main__")

Without the guard, everything at the top level runs on import. Here a module that prints its own demo is imported by a scheduler, and the demo output lands in the scheduler's log.

example-2.py · What goes wrong without the guard
from pathlib import Path
import importlib

Path("labels.py").write_text('''def shelf_label(name, price):
    return f"{name.upper()} ... {price:.2f}"

print(shelf_label("Deluxe Pillow", 47.99))
''', encoding="utf-8")
importlib.invalidate_caches()

print("scheduler starting")
from labels import shelf_label
print(shelf_label("Pro Honey", 5))

When to use it: in every file that can be run directly and might also be imported: utilities, report scripts, data jobs. Tests (see Testing & Code Quality) import your modules too, so a side-effect-free import matters even more later. Mistakes to avoid: misspelling the guard ("main" or "__main"), putting real work at module level "just this once", and calling main() unconditionally at the bottom.

Review
  • __name__ is the module's name when imported and "__main__" in the program you run.
  • Put script work in main() and call it under if __name__ == "__main__":.
  • An import should only define things: no printing, no file reading, no slow work.
  • Next: when an import fails, how to find out why.
Practise this

Loading your progress…

To master this lesson, solve both challenges without hints or the answer, and pass the concept check.

Library and script: the __main__ guard — Modules & Packages · Runtime