Command-line arguments are the simplest interface between a user and your Python program. Everything after the script name lives in sys.argv as a list of strings. A tiny script can parse those strings by hand; anything larger should use argparse, the standard library's declarative parser. It generates the --help text, coerces types, validates choices, and fails with a useful message when the input is wrong.
An argparse parser is typically defined in a few lines. You create an ArgumentParser, add positional arguments (parser.add_argument("path")), add optional flags (parser.add_argument("--verbose", action="store_true")), and call parser.parse_args(). The result is a Namespace with the named attributes.
Every user-facing option should follow two conventions: use -s / --long names, and accept --help for free. argparse wires both up automatically. For subcommands (git add, git commit style) use subparsers; for reading from stdin as a fallback, combine argparse with sys.stdin.
When the user provides interactive input at runtime rather than on the command line, input(prompt) is the built-in primitive. It returns a string; convert with int() or float() and handle the inevitable ValueError. For passwords, getpass.getpass() reads without echoing. For long-running tools, cmd.Cmd or click/typer (third-party) give you richer REPL-style UIs.
argparse basics
add_argument("name", type=int, default=0, help="...") covers typical cases. action="store_true" for boolean flags; choices=[...] for enumerations; required=True on optional arguments; nargs="+" for one-or-more values. Every argument you add appears in the auto-generated help.
For complex tools, group arguments with parser.add_argument_group and register sub-commands with parser.add_subparsers(). Each sub-parser has its own flags, which keeps a busy tool understandable.
Interactive input vs arguments
Arguments are best when the script is automated or embedded in a pipeline. Interactive input() is best when a human runs the script by hand once in a while and wants to be prompted. Many good tools accept both: fall back to input() only when the argument isn't provided.
Always wrap int(input(...)) in a loop that catches ValueError and re-prompts. Trust no input; validate before use.
Command-line tools and helpers.
| Tool | Purpose |
|---|---|
argparse.ArgumentParserclass | Declarative CLI parser. |
parser.add_argumentmethod | Add a positional or optional argument. |
parser.add_subparsersmethod | Register subcommands. |
sys.argvlist | Raw arguments (program name first). |
input(prompt)built-in | Interactive single-line input. |
getpass.getpassfunction | Secret input without echo. |
sys.exit(code)function | Exit with a specific status code. |
sys.stdinstream | Read piped input line by line. |
Handling Command-Line Input code example
The script builds a mini argparse CLI and runs it programmatically so the output is stable for teaching.
# Lesson: Handling Command-Line Input
import argparse
import sys
def build_parser() -> argparse.ArgumentParser:
p = argparse.ArgumentParser(
prog="greet",
description="Greet a user with an optional language.",
)
p.add_argument("name", help="name of the person to greet")
p.add_argument(
"--lang", default="en", choices=["en", "fr", "es"],
help="language for the greeting (default: en)",
)
p.add_argument(
"-n", "--times", type=int, default=1,
help="how many times to repeat (default: 1)",
)
p.add_argument(
"--shout", action="store_true",
help="print the greeting in uppercase",
)
return p
def greet(name: str, lang: str, times: int, shout: bool) -> list[str]:
templates = {"en": "Hello, {}", "fr": "Bonjour, {}", "es": "Hola, {}"}
line = templates[lang].format(name)
if shout:
line = line.upper()
return [line] * times
parser = build_parser()
# Run a few example argument lists as if the user typed them
for argv in (
["Ana"],
["Ben", "--lang", "fr"],
["Cai", "-n", "3", "--shout"],
):
args = parser.parse_args(argv)
print(f"$ greet {' '.join(argv)}")
for line in greet(args.name, args.lang, args.times, args.shout):
print(" ", line)
# Show auto-generated help (also what --help would print)
print("\n--- help text ---")
parser.print_help()
Notice how little ceremony is needed:
1) One positional argument (name) and three options cover a small CLI.
2) `choices=[...]` validates input; bad values produce a clear error automatically.
3) `parser.parse_args(argv)` accepts a list, which is how you test without sys.argv.
4) `print_help()` is what the user sees with `--help`; no manual docs required.
Write a tiny file-stats CLI.
# stats.py (pseudo CLI)
import argparse, sys
from pathlib import Path
def main(argv: list[str] | None = None) -> int:
p = argparse.ArgumentParser()
p.add_argument("path", type=Path)
p.add_argument("-l", "--lines", action="store_true")
args = p.parse_args(argv)
text = args.path.read_text(encoding="utf-8")
if args.lines:
print(len(text.splitlines()))
else:
print(len(text))
return 0
# Run programmatically
from tempfile import NamedTemporaryFile
with NamedTemporaryFile("w", delete=False, encoding="utf-8") as f:
f.write("a\nb\nc\n")
name = f.name
main([name, "--lines"])
Fast checks of the parser.
import argparse
p = argparse.ArgumentParser()
p.add_argument("name")
p.add_argument("--n", type=int, default=1)
assert p.parse_args(["ana", "--n", "3"]).n == 3
try:
p.parse_args([])
except SystemExit:
pass
Running the demo prints:
$ greet Ana
Hello, Ana
$ greet Ben --lang fr
Bonjour, Ben
$ greet Cai -n 3 --shout
HELLO, CAI
HELLO, CAI
HELLO, CAI
--- help text ---
usage: greet [-h] [--lang {en,fr,es}] [-n TIMES] [--shout] name
...