Home Tutorials Standard Library

Standard Library

Command-Line Arguments in Python: sys.argv and argparse

Pyford Notes July 6, 2026 6 min read
Key points
  • sys.argv is a plain list of strings; sys.argv[0] is the script name, the rest are the arguments as typed.
  • argparse.ArgumentParser() builds a parser that validates arguments, converts types, and generates --help automatically.
  • add_argument() with no leading dashes creates a required positional argument; with -- or - it creates an optional flag.
  • type=, default=, and required= on add_argument() control conversion, fallback values, and whether an optional flag must be supplied.

Reading raw arguments with sys.argv

The simplest way to see what was typed on the command line is sys.argv, a list of strings populated automatically when the script runs. The first item is always the script's own path:

# greet.py
import sys

print(sys.argv)
$ python greet.py Ana --loud
['greet.py', 'Ana', '--loud']

sys.argv works, but it hands you raw strings with no validation, no type conversion, and no built-in help — for anything beyond a single fixed argument, argparse is the better tool.

Building a parser with argparse

The standard-library argparse module builds a command-line interface declaratively: describe what arguments the program accepts, and it handles parsing, validation, type conversion, and error messages:

import argparse

parser = argparse.ArgumentParser(description="Greet someone by name.")
parser.add_argument("name")
args = parser.parse_args()

print(f"Hello, {args.name}!")
$ python greet.py Ana
Hello, Ana!

parse_args() reads from sys.argv by default and returns a namespace object whose attributes match the argument names you defined.

Positional and optional arguments

An argument name with no leading dashes is positional — required, and matched by order. An argument name starting with - or -- is optional — matched by flag, and can appear in any order or be omitted:

parser = argparse.ArgumentParser()
parser.add_argument("name")                 # positional, required
parser.add_argument("--loud", action="store_true")   # optional flag

args = parser.parse_args()
greeting = f"HELLO, {args.name.upper()}!" if args.loud else f"Hello, {args.name}!"
print(greeting)
$ python greet.py Ana --loud
HELLO, ANA!

action="store_true" makes --loud a boolean switch: present means True, absent means False, with no value needed after the flag.

Types, defaults, and required flags

add_argument() accepts type= to convert the raw string automatically, default= to supply a fallback when an optional argument is omitted, and required=True to make an otherwise-optional flag mandatory:

parser = argparse.ArgumentParser()
parser.add_argument("--count", type=int, default=1)
parser.add_argument("--output", required=True)

args = parser.parse_args()
print(args.count, args.output)
$ python script.py --output report.txt
1 report.txt

$ python script.py --output report.txt --count 3
3 report.txt

$ python script.py
usage: script.py [-h] --output OUTPUT [--count COUNT]
script.py: error: the following arguments are required: --output

type=int means args.count is already an integer, not a string — argparse raises a clear error itself if the user supplies something that cannot convert, rather than letting a downstream int() call fail with a less helpful traceback.

Automatic help text

Every ArgumentParser automatically supports -h / --help, generating a usage summary from the arguments you defined and any help= text you supplied:

parser = argparse.ArgumentParser(description="Resize an image file.")
parser.add_argument("path", help="Path to the input image")
parser.add_argument("--width", type=int, help="Target width in pixels")
$ python resize.py --help
usage: resize.py [-h] [--width WIDTH] path

Resize an image file.

positional arguments:
  path           Path to the input image

options:
  -h, --help     show this help message and exit
  --width WIDTH  Target width in pixels

This help output stays in sync with the actual argument definitions automatically, since it is generated from the same add_argument() calls rather than maintained as separate documentation that can drift out of date.

Restricting values with choices and nargs

choices= limits an argument to a fixed set of accepted values and rejects anything else with a clear error; nargs= controls how many values a single argument collects:

parser = argparse.ArgumentParser()
parser.add_argument("--level", choices=["low", "medium", "high"], default="medium")
parser.add_argument("--files", nargs="+")   # one or more values, collected into a list

args = parser.parse_args()
print(args.level, args.files)
$ python script.py --level extreme
script.py: error: argument --level: invalid choice: 'extreme' (choose from 'low', 'medium', 'high')

$ python script.py --files a.txt b.txt c.txt
medium ['a.txt', 'b.txt', 'c.txt']

nargs="+" requires at least one value and errors if none are given; nargs="*" allows zero or more. Both settings push validation logic into the parser definition itself, so invalid input is rejected before it ever reaches your program's actual logic, with a message argparse generates automatically.

Subcommands with add_subparsers

Tools like git or docker expose multiple subcommands (git commit, git push) each with their own arguments. add_subparsers() builds this same structure:

parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest="command")

add_parser = subparsers.add_parser("add")
add_parser.add_argument("path")

remove_parser = subparsers.add_parser("remove")
remove_parser.add_argument("path")
remove_parser.add_argument("--force", action="store_true")

args = parser.parse_args()
print(args.command, args.path)
$ python tool.py add report.txt
add report.txt

$ python tool.py remove report.txt --force
remove report.txt

Each subparser behaves like an independent ArgumentParser, with its own positional arguments, optional flags, and --help text, while args.command on the top-level namespace tells you which one was invoked. This scales far better than a single flat parser once a command-line tool grows past one or two distinct actions.