Chapters
Python114 chapters

Modules and the standard libraryChapter 77 of 114

os and sys

Talk to the operating system: environment, paths, and the running interpreter.

Two different jobs

os is the operating system: files, folders, environment variables, processes. sys is the running interpreter: its version, its arguments, its streams.

Environment variables

The right place for configuration that differs between machines, and the only place for secrets:

Python
import os

os.environ["APP_MODE"] = "demo"

print(os.environ["APP_MODE"])
print(os.environ.get("NOT_SET"))
print(os.environ.get("NOT_SET", "a default"))
print("APP_MODE" in os.environ)

Output

demo
None
a default
True

os.environ behaves like a dictionary, so get() with a default is the safe read. Setting one affects this process only; it does not change your shell.

Python
import os

token = os.environ.get("API_TOKEN")
if token is None:
    print("API_TOKEN is not set; refusing to continue")

Output

API_TOKEN is not set; refusing to continue

Never put a key in your source. Read it from the environment and fail loudly when it is missing.

Folders and files

Python
import os

os.makedirs("data/reports", exist_ok=True)

with open("data/reports/march.csv", "w", encoding="utf-8") as f:
    f.write("name,value\n")

print(sorted(os.listdir("data")))
print(os.path.isdir("data/reports"))
print(os.path.isfile("data/reports/march.csv"))
print(os.path.getsize("data/reports/march.csv") > 0)

Output

['reports']
True
True
True

exist_ok=True means "make sure it exists" rather than "create it, and fail if it is there". Without it, running twice raises FileExistsError.

Walking a tree

Python
import os

os.makedirs("tree/inner", exist_ok=True)
for path in ["tree/a.txt", "tree/inner/b.txt"]:
    with open(path, "w", encoding="utf-8") as f:
        f.write("x")

found = []
for folder, subfolders, files in os.walk("tree"):
    for name in files:
        found.append(os.path.join(folder, name).replace(os.sep, "/"))

print(sorted(found))

Output

['tree/a.txt', 'tree/inner/b.txt']

os.walk gives you the folder, its subfolders and its files at every level. pathlib's rglob does the same thing more briefly, and the Paths chapter covers it.

os.path

Python
import os

path = os.path.join("data", "reports", "march.csv")
print(path.replace(os.sep, "/"))
print(os.path.basename(path))
print(os.path.dirname(path).replace(os.sep, "/"))
print(os.path.splitext("march.csv"))

Output

data/reports/march.csv
march.csv
data/reports
('march', '.csv')

os.sep is / on macOS and Linux and \ on Windows, which is why these examples normalise before printing. os.path.join is what stops you hard-coding either one.

sys: the interpreter

Python
import sys

print(sys.version_info >= (3, 10))
print(isinstance(sys.version_info.major, int))
print(len(sys.path) > 0)
print(isinstance(sys.executable, str))

Output

True
True
True
True

These are checked rather than printed because every one differs by machine. sys.executable is the interpreter running right now, and printing it is the fastest answer to "why does my import fail" — usually you installed into a different Python.

sys.argv

Everything typed after the script name:

Python
# greet.py
import sys

print(sys.argv)

if len(sys.argv) < 2:
    print("usage: python greet.py NAME")
    sys.exit(1)

print("Hello,", sys.argv[1])

Output, from a real run elsewhere

['greet.py', 'Ada']
Hello, Ada

sys.argv[0] is the script itself, so real arguments start at 1. For anything beyond one or two, use argparse — the Command-line Arguments chapter covers it.

Exiting, and the streams

Python
import sys

sys.stdout.write("written straight to stdout\n")
print("print goes there too")

Output

written straight to stdout
print goes there too

Errors and progress belong on the other stream:

Python
import sys

sys.stderr.write("this goes to stderr\n")

Output

this goes to stderr

Keeping them apart means piping a program's output into a file or another command captures the data without the chatter.

sys.exit(0) means success and any other number means failure, which is what a shell script checks.

Test yourself

2 questions

Where should an API key come from?

Show the answer

os.environ, read with a default and checked — Anything in the source ends up in version control. Read it from the environment and fail loudly when it is missing.

What does os.makedirs(path, exist_ok=True) do differently?

Show the answer

It succeeds when the folder is already there — Without it, running your script twice raises FileExistsError.

Next chapter

Random Numbers

Pick, shuffle and sample, and know when random is not good enough.