Command-Line Scripts with argparse
Let users hand your script its inputs
In this lesson
argparse is Python’s built-in module for building command-line tools. A script you have to edit before every run isn’t really a tool — argparse lets users pass inputs on the command line (python clean.py report.csv --uppercase) and gives you help text and error messages for free. This lesson builds a small CLI step by step.
Explain it like I’m 5
Command-line arguments are the instructions you hand a script when you start it, like telling a vending machine which button you want instead of rewiring it each time.
From hardcoded values to arguments
The slow way is to edit variables in the file for every run. That’s fine once, but painful when the script becomes something you use daily. Command-line arguments let the user supply those values at launch instead, so the code stays put.
# Hardcoded: you must open the file and edit it every time
filename = "report.csv"
uppercase = True
print("cleaning", filename, "uppercase =", uppercase)
cleaning report.csv uppercase = True
argparse: positionals, options, and flags
You create a parser, declare the arguments you expect, then call parse_args(). A positional argument is required and identified by position; an option (starting with --) is named and usually optional; a flag with action="store_true" is simply present or absent. Here we pass the arguments as a list so it runs in the browser, but on a real machine parse_args() reads them from the command line automatically.
import argparse
parser = argparse.ArgumentParser(description="Clean a CSV file")
parser.add_argument("filename") # required positional
parser.add_argument("--uppercase", action="store_true") # on/off flag
args = parser.parse_args(["report.csv", "--uppercase"])
print(args.filename, args.uppercase)
report.csv True
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("name")
parser.add_argument("--times", type=int, default=1)
args = parser.parse_args(["Ada", "--times", "3"])
for _ in range(args.times):
print("Hello", args.name)
Hello Ada Hello Ada Hello Ada
Build a tiny greeter CLI
Put the pieces together: one required value and one flag that changes behaviour.
Build a parser that takes a required name and an optional --shout flag. Start from f"Hello {args.name}", and when --shout is given, print the greeting in capitals.
import argparse
parser = argparse.ArgumentParser()
# TODO: add a positional "name" argument
# TODO: add an optional "--shout" flag (action="store_true")
args = parser.parse_args(["Ada", "--shout"])
greeting = f"Hello {args.name}"
# TODO: if args.shout, uppercase the greeting
print(greeting)
Add parser.add_argument("name") and parser.add_argument("--shout", action="store_true"), then greeting = greeting.upper() when args.shout is true.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("name")
parser.add_argument("--shout", action="store_true")
args = parser.parse_args(["Ada", "--shout"])
greeting = f"Hello {args.name}"
if args.shout:
greeting = greeting.upper()
print(greeting)
HELLO ADA
Common mistake: Reading sys.argv by index instead of using argparse
sys.argv[1] looks simpler for one argument, so it sneaks in early.
Use argparse as soon as you have more than one argument or any optional one. It handles order, defaults, types, missing values, and help — all the parts hand-rolled sys.argv code gets wrong.
Common mistake: Forgetting type= so numbers arrive as strings
argparse hands you every value as a string by default, and "3" looks close enough to 3 until you do maths with it.
Pass type=int (or type=float) so the value is converted for you and bad input is rejected with a clear message.
Common mistake: Expecting a flag to carry a value
A store_true flag is either present or absent, but it’s easy to write --shout yes as if it took a word.
For an on/off switch use action="store_true" and just include or omit the flag. Use a normal option (no store_true) when you actually need a value.
What does argparse generate automatically from your add_argument calls?
argparse builds --help output and error messages for you from the arguments you declare.
What is a flag created with action="store_true"?
A store_true flag is a simple on/off switch — its presence sets the value to True.
Why pass type=int to an argument?
argparse gives strings by default; type=int converts the value and rejects non-numbers.
Mini exercise (medium)
Build a CLI that takes a required width and height as integers and an optional --unit (default "cm"), then prints the area like 20 sq cm. Parse the arguments ["5", "4"] so the default unit is used.
Do it here. Finish the code below and press Run to try your answer right in the browser — no setup needed.
import argparse
parser = argparse.ArgumentParser()
# TODO: add width and height as integers, and an optional --unit (default "cm")
args = parser.parse_args(["5", "4"])
area = 0 # TODO: width * height
print(f"{area} sq {args.unit}")
Use type=int on both positionals and default="cm" on --unit, then print an f-string: f"{area} sq {args.unit}".
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("width", type=int)
parser.add_argument("height", type=int)
parser.add_argument("--unit", default="cm")
args = parser.parse_args(["5", "4"])
area = args.width * args.height
print(f"{area} sq {args.unit}")
20 sq cm
assert area == 20, "area should be width * height = 20"
assert args.unit == "cm", "--unit should default to cm when not given"
assert isinstance(args.width, int), "width should be parsed as an int (use type=int)"
print("✓ CLI parsed!")