Modules & ErrorsLesson 2 of 3
Scripts & __main__
Every Python file can be both a module you import and a script you run. Python tells the two cases apart with a special variable: __name__. When you run python app.py, the code in app.py runs with __name__ set to "__main__". When another file does import app, the same code runs with __name__ set to "app".
That is why almost every Python script ends with the main guard: if __name__ == "__main__": main(). Code inside the guard runs only when the file is executed directly, never when it is imported. Without it, importing your module to reuse one function would also start the whole program. It is the equivalent of Node's require.main === module check (or import.meta.main in Deno and Bun), except that in Python everyone uses it.
You can also run a module by its import path with python -m: python -m myapp.cli runs myapp/cli.py as __main__, with imports resolved from the project root. Many tools work this way: python -m venv, python -m pip, python -m http.server, python -m pytest.
Command-line arguments live in sys.argv. Unlike process.argv, where [0] is the node binary and [1] is the script, sys.argv[0] is the script name and the real arguments start at sys.argv[1]. For anything beyond one or two arguments, use the built-in argparse module (think yargs or commander, but in the standard library): it parses flags, converts types, applies defaults, and generates --help for free.
Finally, exit codes: sys.exit(0) means success and any non-zero number means failure, exactly like process.exit(). A common pattern is to write def main() -> int: ... and finish with sys.exit(main()) inside the main guard.
Quick reference
| JavaScript | Python | Note |
|---|---|---|
| require.main === module | if __name__ == "__main__": | Run only when executed directly |
| node scripts/build.js | python -m scripts.build | Run a module by import path |
| process.argv.slice(2) | sys.argv[1:] | argv[0] is the script name |
| yargs / commander | argparse | Built into the standard library |
| process.exit(1) | sys.exit(1) | Non-zero = failure |
Side by side
// Node.js: greet.js
function main(argv) {
const [name = "World"] = argv;
const times = Number(argv[1] ?? 1);
for (let i = 0; i < times; i++) {
console.log(`Hello, ${name}!`);
}
return 0;
}
if (require.main === module) {
process.exit(main(process.argv.slice(2)));
}
// node greet.js Ada 2# Python: greet.py
import argparse
import sys
def main(argv=None):
parser = argparse.ArgumentParser(description="Greet someone")
parser.add_argument("name")
parser.add_argument("--times", type=int, default=1)
args = parser.parse_args(argv) # None -> uses sys.argv[1:]
for _ in range(args.times):
print(f"Hello, {args.name}!")
return 0
if __name__ == "__main__":
sys.exit(main())
# python greet.py Ada --times 2
# python greet.py --help (generated for free)Exercise
Real Python, running in your browserWrite a small command-line script with argparse and a main guard:
Hello, World! Hello, World!
Ctrl + Enter runCtrl + Shift + Enter checkTab indentEsc then Tab to leave the editorCtrl + / comment