Skip to content

Python argparse & sys.argv — CLI Arguments

When you run a script from the terminal, the words after the script name are command-line arguments. Python gives you two ways to read them: the raw sys.argv list, and the full-featured argparse library.

run_example.py
# $ python greet.py Ada --times 3
import sys
print(sys.argv)   # ['greet.py', 'Ada', '--times', '3']

sys.argv is a list of strings. The first item is always the script name; the rest are the arguments, as strings.

sys_argv.py
import sys
 
# $ python add.py 3 4
if len(sys.argv) != 3:
    print("Usage: python add.py NUM NUM")
    sys.exit(1)
 
a = int(sys.argv[1])    # convert from string!
b = int(sys.argv[2])
print(a + b)            # 7

sys.argv is fine for one or two arguments, but it forces you to handle conversion, validation, defaults, and help text by hand. For anything real, use argparse.

argparse parses arguments, converts types, generates --help, and reports errors automatically.

argparse_basic.py
import argparse
 
parser = argparse.ArgumentParser(description="Greet someone.")
parser.add_argument("name", help="who to greet")
parser.add_argument("--times", type=int, default=1, help="how many times")
 
args = parser.parse_args()           # reads from sys.argv
for _ in range(args.times):
    print(f"Hello, {args.name}!")

Running it:

terminal
$ python greet.py Ada --times 2
Hello, Ada!
Hello, Ada!
 
$ python greet.py --help
usage: greet.py [-h] [--times TIMES] name
...
KindDefined asExample
Positionaladd_argument("name")python app.py Ada
Optionaladd_argument("--times")python app.py --times 3
Flagadd_argument("--verbose", action="store_true")python app.py --verbose
positional_optional.py
import argparse
 
parser = argparse.ArgumentParser()
parser.add_argument("filename")                      # required positional
parser.add_argument("--limit", type=int, default=10) # optional with default
parser.add_argument("--verbose", action="store_true")# flag -> True/False
 
# parse_args can take an explicit list (handy for testing)
args = parser.parse_args(["data.txt", "--limit", "5", "--verbose"])
print(args.filename)   # data.txt
print(args.limit)      # 5
print(args.verbose)    # True

Tip: parse_args() reads sys.argv by default, but you can pass a list — parse_args(["a", "b"]) — which is perfect for tests and examples.

OptionEffect
type=intConvert the value (to int, float, etc.).
default=...Value used when the argument is omitted.
required=TrueMake an optional argument mandatory.
choices=[...]Restrict to a fixed set of values.
action="store_true"Boolean flag (no value needed).
nargs="+"Accept multiple values into a list.
help="..."Text shown in --help.
advanced.py
import argparse
 
parser = argparse.ArgumentParser()
parser.add_argument("--mode", choices=["fast", "safe"], default="safe")
parser.add_argument("--files", nargs="+")   # one or more values
args = parser.parse_args(["--mode", "fast", "--files", "a.txt", "b.txt"])
print(args.mode)    # fast
print(args.files)   # ['a.txt', 'b.txt']

Add a one-letter alias alongside the long name:

short_flags.py
import argparse
 
parser = argparse.ArgumentParser()
parser.add_argument("-n", "--number", type=int, default=1)
args = parser.parse_args(["-n", "7"])
print(args.number)   # 7
  • sys.argv values are strings — convert with int()/float().
  • sys.argv[0] is the script name, not the first argument.
  • Dashes become underscores--max-size is read as args.max_size.
  • store_true flags default to False — presence flips them to True.
  • argparse exits on bad input — it prints usage and calls sys.exit, which is usually what you want.

Exercise 2 – Parse a positional argument

Section titled “Exercise 2 – Parse a positional argument”

Exercise 3 – An optional integer with a default

Section titled “Exercise 3 – An optional integer with a default”
diagram sys.argv is a list; argparse is a parser that can exit mermaid
Reading sys.argv directly means writing your own validation, conversion and help text. argparse does those and, when something is wrong, prints usage and terminates the process -- which is correct for a command-line tool and surprising inside a library or a test.
sketch What argparse does before your first line runs p5.js
The parser is not only a reader. It checks that required arguments are present, converts each value with the type you declared, and on failure prints the usage line and exits the process with status 2. Everything your code sees afterwards has already been validated -- which is why there is no error handling in a well-written main().
pch.quizTag pch.quizDefaultTitle
  1. What is `sys.argv[0]`?

    pch.quizShowAnswer

    B — The script name — Verified: with no arguments, `len(sys.argv)` is 1. The first real argument is `sys.argv[1]`, which is the usual off-by-one in hand-rolled argument parsing.

  2. `--dry-run` with `action='store_true'`. How do you read it from the Namespace?

    pch.quizShowAnswer

    B — `ns.dry_run` — The dash becomes an underscore. `ns.dry-run` is a syntax error and `getattr(ns, 'dry-run')` returns nothing useful, so the flag appears to be ignored.

  3. `-n abc` where `-n` was declared `type=int`. What does `parse_args()` do?

    pch.quizShowAnswer

    C — Prints usage and raises `SystemExit(2)` — Verified. That is right for a command-line tool and wrong inside a library or a test — there, catch `SystemExit` or use `parse_known_args`.

  4. What does argparse guarantee about the values your code receives?

    pch.quizShowAnswer

    B — They are present and already converted to the declared types — A missing required argument or a bad conversion stops the program before your code runs, which is why a well-written `main()` needs no argument checking of its own.

  • sys.argv is the raw list of string arguments (argv[0] is the script name).
  • argparse adds types, defaults, choices, flags, validation, and auto-generated --help.
  • Positional args are required; --optional args can have defaults; store_true makes boolean flags.
  • Pass an explicit list to parse_args([...]) for testing and examples.

pch.coffeeTagline

pch.coffeeCta

pch.feedbackHeading

pch.feedbackSubheading