Python command line arguments are the words you type after the script name, like python report.py sales.csv 2026. Python stores them in sys.argv, a list of strings. For named options, defaults and a free --help page, use the argparse module:
import sys
print(sys.argv[1:]) # python report.py sales.csv 2026 -> ['sales.csv', '2026']
Every script below was saved to a folder and started from a Windows Command Prompt on Python 3.12.5, so the output blocks and screenshots are exactly what the terminal printed.
In this tutorial, we’ll start with raw sys.argv, make it safe, then switch to argparse for options, flags, choices and subcommands. I’ll finish with getopt and a quick guide to picking one.
What are command-line arguments in Python?
A command-line argument is any value you add after the file name when you start a script. They let one script handle different files, dates or settings without editing the code each time.
Python puts them in sys.argv. Item 0 is the script name, and the rest are your arguments, split on spaces. I ran this three-line script with no arguments, three arguments, and a quoted city name:
import sys
print("Script: ", sys.argv[0])
print("Arguments:", sys.argv[1:])
print("Count: ", len(sys.argv) - 1)
Output:
C:\pyguides> python show_args.py
Script: show_args.py
Arguments: []
Count: 0
C:\pyguides> python show_args.py report.csv 2026-10-20 --verbose
Script: show_args.py
Arguments: ['report.csv', '2026-10-20', '--verbose']
Count: 3
C:\pyguides> python show_args.py "San Francisco" 3
Script: show_args.py
Arguments: ['San Francisco', '3']
Count: 2

sys.argv[1:] is empty with no arguments; quotes keep "San Francisco" together as one item.Two details matter here. '3' and '2026-10-20' arrive as strings, and --verbose is just another string in the list. sys.argv doesn’t parse or convert anything.
If you haven’t started a script from a terminal before, my guide on how to run a Python script covers opening Command Prompt and moving to the right folder.
Why does sys.argv[1] raise an IndexError?
Reading sys.argv[1] directly works until someone forgets the argument. Then the list only holds the script name, and Python raises an IndexError:
import sys
city = sys.argv[1]
print(f"Weather report for {city}")
Output:
C:\pyguides> python weather.py Boston
Weather report for Boston
C:\pyguides> python weather.py
Traceback (most recent call last):
File "C:\pyguides\weather.py", line 3, in <module>
city = sys.argv[1]
~~~~~~~~^^^
IndexError: list index out of range

Boston the script works; without it, sys.argv[1] doesn’t exist and the traceback says list index out of range.A traceback like this confuses anyone who just wants to run your tool. The fix is to check len(sys.argv) first and print a usage line. More causes of this error are in fixing IndexError: list index out of range.
Validate and convert sys.argv values to numbers
This sales-tax calculator expects exactly two values. It checks the count, converts both strings with float(), and catches the ValueError you get when the text isn’t a number:
import sys
if len(sys.argv) != 3:
print("Usage: python sales_tax.py PRICE RATE")
sys.exit(1)
try:
price = float(sys.argv[1])
rate = float(sys.argv[2])
except ValueError:
print("Error: PRICE and RATE must be numbers, e.g. 49.99 0.0825")
sys.exit(1)
tax = price * rate
print(f"Price: ${price:.2f}")
print(f"Tax: ${tax:.2f}")
print(f"Total: ${price + tax:.2f}")
Output:
C:\pyguides> python sales_tax.py 49.99 0.0825
Price: $49.99
Tax: $4.12
Total: $54.11
C:\pyguides> python sales_tax.py 49.99
Usage: python sales_tax.py PRICE RATE
C:\pyguides> python sales_tax.py fifty 0.0825
Error: PRICE and RATE must be numbers, e.g. 49.99 0.0825

fifty triggers the number error.A $49.99 item at 8.25% tax comes to $54.11. The conversion step is the same one I cover in converting a string to a float in Python, and the try/except is plain Python exception handling.
sys.exit(1) stops the script and reports failure to the shell. A non-zero exit code is how batch files, schedulers and CI jobs know something went wrong.
This works, but you can see the pattern growing. Every new value needs its own count check, conversion and message. That’s the point where argparse saves real code.
Parse command-line arguments with argparse
argparse is in the standard library, so there’s nothing to install. You create a parser, describe each argument with add_argument(), and call parse_args(). Here’s a road-trip gas calculator:
import argparse
parser = argparse.ArgumentParser(description="Estimate the gas cost of a road trip.")
parser.add_argument("miles", type=float, help="one-way distance in miles")
parser.add_argument("--mpg", type=float, default=28.0, help="car fuel economy (default: 28)")
parser.add_argument("--price", type=float, default=3.45, help="gas price per gallon in USD (default: 3.45)")
parser.add_argument("-r", "--round-trip", action="store_true", help="double the distance")
args = parser.parse_args()
miles = args.miles * 2 if args.round_trip else args.miles
gallons = miles / args.mpg
print(f"Distance: {miles:,.0f} miles")
print(f"Gas used: {gallons:.1f} gallons")
print(f"Cost: ${gallons * args.price:.2f}")
Output:
C:\pyguides> python trip_cost.py 380
Distance: 380 miles
Gas used: 13.6 gallons
Cost: $46.82
C:\pyguides> python trip_cost.py 380 --mpg 34 --price 3.89 -r
Distance: 760 miles
Gas used: 22.4 gallons
Cost: $86.95

-r for a round trip.miles is a positional argument: no dashes, required, and read by position. --mpg and --price are optional arguments with defaults, and type=float converts the text for you.
--round-trip uses action="store_true", so it’s a flag. It’s False unless you type it. -r is its short form, and argparse turns the dash in round-trip into args.round_trip.
Defaults on the command line behave like default parameters in a function, which I explain in Python functions with optional arguments.
The –help page and error messages argparse writes for you
You never wrote a help screen, yet -h prints one built from the help= strings. Missing or badly typed values are rejected before your code runs:
import argparse
parser = argparse.ArgumentParser(description="Estimate the gas cost of a road trip.")
parser.add_argument("miles", type=float, help="one-way distance in miles")
parser.add_argument("--mpg", type=float, default=28.0, help="car fuel economy (default: 28)")
parser.add_argument("--price", type=float, default=3.45, help="gas price per gallon in USD (default: 3.45)")
parser.add_argument("-r", "--round-trip", action="store_true", help="double the distance")
args = parser.parse_args()
miles = args.miles * 2 if args.round_trip else args.miles
gallons = miles / args.mpg
print(f"Distance: {miles:,.0f} miles")
print(f"Gas used: {gallons:.1f} gallons")
print(f"Cost: ${gallons * args.price:.2f}")
Output:
C:\pyguides> python trip_cost.py -h
usage: trip_cost.py [-h] [--mpg MPG] [--price PRICE] [-r] miles
Estimate the gas cost of a road trip.
positional arguments:
miles one-way distance in miles
options:
-h, --help show this help message and exit
--mpg MPG car fuel economy (default: 28)
--price PRICE gas price per gallon in USD (default: 3.45)
-r, --round-trip double the distance
C:\pyguides> python trip_cost.py
usage: trip_cost.py [-h] [--mpg MPG] [--price PRICE] [-r] miles
trip_cost.py: error: the following arguments are required: miles
C:\pyguides> python trip_cost.py 380 --mpg high
usage: trip_cost.py [-h] [--mpg MPG] [--price PRICE] [-r] miles
trip_cost.py: error: argument --mpg: invalid float value: 'high'

-h lists every argument with its default; leaving out miles or typing high for mpg prints the usage line and a clear error.On an error, argparse prints the usage line and exits with code 2. After -h it exits with 0. Both happen inside parse_args(), so the lines after it never run.
How do you add choices, lists and verbosity flags in argparse?
Most real tools need more than a number and a flag. add_argument() handles the common cases with keyword arguments. Passing a list to parse_args() lets you try them without a terminal:
import argparse
parser = argparse.ArgumentParser(prog="ship")
parser.add_argument("--carrier", choices=["ups", "fedex", "usps"], required=True)
parser.add_argument("--zip", dest="zip_codes", nargs="+", help="one or more ZIP codes")
parser.add_argument("-v", "--verbose", action="count", default=0)
parser.add_argument("--weight", type=float, default=1.0, metavar="LBS")
args = parser.parse_args(["--carrier", "ups", "--zip", "10001", "60601", "94105", "-vv"])
print(args)
print("ZIP codes:", args.zip_codes)
print("Verbosity level:", args.verbose)
print("As a dict:", vars(a