Python argparse Tutorial: Build Command-Line Interfaces
Introduction
You have probably run commands like this in a terminal:
python script.py --input data.csv --output results.csv --verbose
Those --input, --output, and --verbose flags are command-line arguments. The argparse module — part of Python’s standard library — lets you add them to any script in minutes.
Without argparse, you would parse sys.argv manually. With it, you get automatic help messages, type validation, and error handling for free.
All examples are tested on Python 3.12.
The Simplest Case
import argparse
parser = argparse.ArgumentParser(description="A simple example script")
parser.add_argument("name", help="Your name")
args = parser.parse_args()
print(f"Hello, {args.name}!")
Run it:
python greet.py Alice
Expected output:
Hello, Alice!
Run it with --help:
python greet.py --help
Expected output:
usage: greet.py [-h] name
A simple example script
positional arguments:
name Your name
options:
-h, --help show this help message and exit
argparse generates the help message automatically from your argument definitions.
Positional vs Optional Arguments
Positional Arguments
Positional arguments are required and identified by their position:
parser.add_argument("filename", help="File to process")
parser.add_argument("output", help="Output file path")
python script.py input.txt output.txt
Optional Arguments
Optional arguments start with -- and can appear in any order:
parser.add_argument("--verbose", help="Enable verbose output", action="store_true")
parser.add_argument("--count", help="Number of items", type=int, default=10)
python script.py --verbose --count 5
action="store_true" means the flag stores True when present, False when absent — no value needed.
Types and Defaults
By default, all arguments are strings. Use type= to convert automatically:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--count", type=int, default=10)
parser.add_argument("--threshold", type=float, default=0.5)
parser.add_argument("--name", type=str, default="world")
args = parser.parse_args()
print(f"Count: {args.count} ({type(args.count).__name__})")
print(f"Threshold: {args.threshold}")
print(f"Name: {args.name}")
Run with no arguments:
python script.py
Expected output:
Count: 10 (int)
Threshold: 0.5
Name: world
Run with custom values:
python script.py --count 25 --threshold 0.8 --name Alice
Expected output:
Count: 25 (int)
Threshold: 0.8
Name: Alice
Short Flags
Add a short version of an argument with -:
parser.add_argument("-v", "--verbose", action="store_true", help="Verbose output")
parser.add_argument("-n", "--count", type=int, default=10, help="Number of items")
Now both of these work:
python script.py --verbose --count 5
python script.py -v -n 5
Required Optional Arguments
Optional arguments are optional by default, but you can make them required:
parser.add_argument("--output", required=True, help="Output file path")
If the user forgets --output, argparse shows an error:
error: the following arguments are required: --output
Choices — Restricting Values
Use choices= to limit an argument to specific values:
parser.add_argument(
"--format",
choices=["json", "csv", "xml"],
default="json",
help="Output format"
)
parser.add_argument(
"--log-level",
choices=["DEBUG", "INFO", "WARNING", "ERROR"],
default="INFO"
)
If the user passes an invalid value, argparse shows a clear error message automatically.
Multiple Values with nargs
Accept multiple values for a single argument:
parser.add_argument("--files", nargs="+", help="One or more input files")
parser.add_argument("--numbers", nargs=3, type=int, help="Exactly 3 numbers")
parser.add_argument("--tags", nargs="*", help="Zero or more tags")
python script.py --files a.txt b.txt c.txt --numbers 1 2 3
args.files becomes ["a.txt", "b.txt", "c.txt"] and args.numbers becomes [1, 2, 3].
A Real Example: File Processor
import argparse
from pathlib import Path
def process_file(input_path, output_path, uppercase, max_lines):
with open(input_path, "r") as f:
lines = f.readlines()
if max_lines:
lines = lines[:max_lines]
if uppercase:
lines = [line.upper() for line in lines]
with open(output_path, "w") as f:
f.writelines(lines)
print(f"Processed {len(lines)} lines → {output_path}")
def main():
parser = argparse.ArgumentParser(
description="Process a text file",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
python processor.py input.txt output.txt
python processor.py input.txt output.txt --uppercase
python processor.py input.txt output.txt --max-lines 100
"""
)
parser.add_argument("input", type=Path, help="Input file path")
parser.add_argument("output", type=Path, help="Output file path")
parser.add_argument("--uppercase", "-u", action="store_true", help="Convert to uppercase")
parser.add_argument("--max-lines", "-n", type=int, help="Maximum number of lines to process")
args = parser.parse_args()
if not args.input.exists():
parser.error(f"Input file not found: {args.input}")
process_file(args.input, args.output, args.uppercase, args.max_lines)
if __name__ == "__main__":
main()
Subcommands
For tools with multiple modes (like git commit, git push), use subparsers:
import argparse
parser = argparse.ArgumentParser(description="Simple task manager")
subparsers = parser.add_subparsers(dest="command", required=True)
# 'add' subcommand
add_parser = subparsers.add_parser("add", help="Add a task")
add_parser.add_argument("task", help="Task description")
# 'list' subcommand
list_parser = subparsers.add_parser("list", help="List all tasks")
list_parser.add_argument("--all", action="store_true", help="Show completed tasks too")
# 'done' subcommand
done_parser = subparsers.add_parser("done", help="Mark task as done")
done_parser.add_argument("id", type=int, help="Task ID")
args = parser.parse_args()
if args.command == "add":
print(f"Adding task: {args.task}")
elif args.command == "list":
print(f"Listing tasks (show all: {args.all})")
elif args.command == "done":
print(f"Marking task {args.id} as done")
Usage:
python tasks.py add "Buy groceries"
python tasks.py list --all
python tasks.py done 3
python tasks.py --help
Quick Reference
| Feature | Code |
|---|---|
| Positional argument | parser.add_argument("name") |
| Optional flag | parser.add_argument("--verbose") |
| Short flag | parser.add_argument("-v", "--verbose") |
| With type | parser.add_argument("--count", type=int) |
| With default | parser.add_argument("--count", default=10) |
| Required | parser.add_argument("--output", required=True) |
| Boolean flag | parser.add_argument("--flag", action="store_true") |
| Limited choices | parser.add_argument("--fmt", choices=["json","csv"]) |
| Multiple values | parser.add_argument("--files", nargs="+") |
Wrap-Up
argparse turns any Python script into a proper command-line tool with minimal code. The help message, type validation, and error handling come for free — no manual sys.argv parsing needed.
For scripts that run on a schedule, combine argparse with the scheduling guide to pass different arguments on different runs. For questions or future tutorial ideas, get in touch via the Contact page.