ATOC 4815/5815

Passing Variables to Python Scripts

Will Chapman

CU Boulder ATOC

Spring 2026

Passing Variables to Python Scripts

Today’s Objectives

  • Understand why hard-coded values limit your science
  • Read command-line arguments with sys.argv (the low-level way)
  • Build proper CLI interfaces with argparse
  • Add types, defaults, and help text to your arguments
  • Handle common errors gracefully

The Hard-Coding Problem

You’ve Seen This Before

You wrote a script that analyzes temperature data:

# analyze_climate.py
import numpy as np

data    = np.load("boulder_temps_2023.npy")
thresh  = 35.0          # ← hard-coded
n_days  = 90            # ← hard-coded
outfile = "output.png"  # ← hard-coded

hot_days = np.sum(data[:n_days] > thresh)
print(f"Days above {thresh}°C in first {n_days} days: {hot_days}")

What if you want to test a different threshold? Edit the file. Run. Edit again. Run again…

What if a collaborator wants to use it? They edit the file. Now you have two versions.

The Goal

python analyze_climate.py --thresh 30 --n-days 180 --outfile summer.png
python analyze_climate.py --thresh 40 --n-days 365 --outfile extreme.png

Same script. Different science. No file edits.

The Low-Level Way: sys.argv

sys.argv: What the Shell Sends Python

Every time you run a Python script, the shell sends a list of strings called sys.argv:

python myscript.py Boulder 35.0 90
import sys
print(sys.argv)
# ['myscript.py', 'Boulder', '35.0', '90']
#       ↑              ↑        ↑      ↑
#   index 0         index 1  index 2  index 3

You can read these manually:

import sys

city   = sys.argv[1]
thresh = float(sys.argv[2])   # ← must convert from string yourself!
n_days = int(sys.argv[3])

print(f"City: {city}, Threshold: {thresh}°C, Days: {n_days}")

Why sys.argv Alone Is Fragile

  • No automatic type conversion — everything arrives as a string
  • No defaults — crash if user forgets an argument
  • No help text — user has to read the source to know what to pass
  • Order-dependent — easy to mix up arguments

argparse

What Is argparse?

argparse is a standard library module — it ships with Python, no install needed.

It does three things for you automatically:

What you need Without argparse With argparse
Convert "35.0"float float(sys.argv[2]) by hand type=float
Fallback when arg is missing try/except IndexError default=35.0
Tell users how to run the script Write a README --help is auto-generated
Catch bad input early Crash deep in your code Clear error before main() runs
# This is what argparse gives you for free:
$ python analyze_climate.py --help
usage: analyze_climate.py [-h] [--thresh THRESH] [--n-days N_DAYS]

Analyze temperature extremes.

options:
  -h, --help       show this help message and exit
  --thresh THRESH  temperature threshold in °C (default: 35.0)
  --n-days N_DAYS  number of days to analyze (default: 90)

argparse in Four Steps

import argparse

# 1. Create a parser
parser = argparse.ArgumentParser(description="Analyze temperature extremes.")

# 2. Define your arguments
parser.add_argument("--thresh",  type=float, default=35.0, help="temperature threshold (°C)")
parser.add_argument("--n-days",  type=int,   default=90,   help="number of days to analyze")
parser.add_argument("--outfile", type=str,   default="output.png", help="output figure path")

# 3. Parse the command line
args = parser.parse_args()

# 4. Use args like object attributes
print(f"Threshold: {args.thresh}")
print(f"Days:      {args.n_days}")   # note: hyphens become underscores
print(f"Output:    {args.outfile}")

Now --help works automatically:

$ python analyze_climate.py --help
usage: analyze_climate.py [-h] [--thresh THRESH] [--n-days N_DAYS] [--outfile OUTFILE]

Analyze temperature extremes.

options:
  --thresh THRESH    temperature threshold (°C) (default: 35.0)
  --n-days N_DAYS    number of days to analyze (default: 90)
  --outfile OUTFILE  output figure path (default: output.png)

Putting It All Together

# analyze_climate.py
import argparse
import numpy as np

def main():
    parser = argparse.ArgumentParser(
        description="Count days exceeding a temperature threshold."
    )
    parser.add_argument("--datafile", type=str,   required=True,      help="path to .npy temperature file")
    parser.add_argument("--thresh",   type=float, default=35.0,       help="threshold in °C (default: 35)")
    parser.add_argument("--n-days",   type=int,   default=None,       help="limit analysis to first N days")
    parser.add_argument("--outfile",  type=str,   default="out.png",  help="output figure filename")
    args = parser.parse_args()

    data = np.load(args.datafile)
    if args.n_days is not None:
        data = data[:args.n_days]

    hot_days = np.sum(data > args.thresh)
    print(f"Days above {args.thresh}°C: {hot_days} / {len(data)}")
    # ... plotting code here ...

if __name__ == "__main__":
    main()
# Use all defaults
python analyze_climate.py --datafile boulder_2023.npy

# Override threshold and limit to summer
python analyze_climate.py --datafile boulder_2023.npy --thresh 38 --n-days 92 --outfile summer.png

Key add_argument Options

Option What it does Example
type= Converts string → Python type automatically type=float
default= Value used when argument is omitted default=35.0
required=True Crashes with a clear message if omitted for mandatory inputs
help= Text shown in --help output help="threshold in °C"
choices= Restricts to a list of valid values choices=["mean","max","min"]
nargs="+" Accepts one or more values as a list --years 2020 2021 2022

Hyphens vs underscores: --n-days on the command line → args.n_days in code. argparse converts automatically.

Positional vs Optional Arguments

  • --thresh (two dashes) → optional, can be omitted if it has a default
  • datafile (no dashes) → positional, must be provided in order

Common Errors

Predict the Error

What happens when you run this?

python analyze_climate.py --thresh warm
parser.add_argument("--thresh", type=float, default=35.0, help="threshold in °C")
error: argument --thresh: invalid float value: 'warm'

argparse catches the bad type before your code even runs. Compare this to sys.argv, where you’d get a cryptic ValueError deep inside your script.

Another common mistake — forgetting if __name__ == "__main__":

# Bad: parser runs even when the file is imported as a module
args = parser.parse_args()

# Good: only parse when the script is run directly
if __name__ == "__main__":
    main()

Check Your Understanding

Try It

You want to run an ensemble weather simulation with a configurable number of members and random seed:

python run_ensemble.py --n-members 50 --seed 42 --outdir ./results/

Write the add_argument calls (don’t write the full script — just the three lines):

parser.add_argument("--n-members", type=int,   default=30,        help="ensemble size")
parser.add_argument("--seed",      type=int,   default=0,         help="random seed for reproducibility")
parser.add_argument("--outdir",    type=str,   default="./output", help="directory to save results")

Bonus: what is args.n_members (not args.n-members) and why?

Hyphens in argument names are replaced with underscores in args — Python identifiers can’t contain hyphens.

Key Takeaways

  • Hard-coding kills reproducibility — never embed run parameters directly in source code
  • sys.argv gives raw access to command-line strings, but you handle all conversion and errors yourself
  • argparse gives you type conversion, defaults, help text, and error messages for free
  • Wrap your script logic in main() and guard with if __name__ == "__main__" — this makes it both runnable and importable
  • Use required=True for inputs that genuinely have no sensible default (like an input data file)
  • Your collaborators will thank you for --help

Questions?

Office Hours:

Will: Tu 11:15-12:15p / Th 9-10a Aerospace Café

Aiden: M / W 3:30-4:30p DUAN D319

Useful docs:

Quick reference:

import argparse

parser = argparse.ArgumentParser(
    description="My script."
)
parser.add_argument(
    "--param",
    type=float,
    default=1.0,
    help="a parameter"
)
args = parser.parse_args()
print(args.param)