Python Programming

Files, Errors and Exceptions

35 דק׳

Paths with pathlib

from pathlib import Path
data_dir = Path("data")
data_dir.mkdir(exist_ok=True)
report = data_dir / "report.txt"
report.exists()
for p in data_dir.glob("*.csv"):
    print(p.name, p.stat().st_size)

pathlib works on every operating system; avoid building paths with string concatenation.

Reading and writing text

report.write_text("Total: 42\n", encoding="utf-8")
content = report.read_text(encoding="utf-8")

with open("log.txt", "a", encoding="utf-8") as fh:   # a = append
    fh.write("started\n")

with open("big.log", encoding="utf-8") as fh:
    for line in fh:          # streams line by line, any file size
        if "ERROR" in line:
            print(line.rstrip())

The with block closes the file even if an error happens. Always pass encoding="utf-8".

CSV and JSON

import csv, json

with open("users.csv", newline="", encoding="utf-8") as fh:
    users = list(csv.DictReader(fh))

with open("out.csv", "w", newline="", encoding="utf-8") as fh:
    writer = csv.DictWriter(fh, fieldnames=["email", "points"])
    writer.writeheader()
    writer.writerows(users)

settings = json.loads(Path("settings.json").read_text())
Path("settings.json").write_text(json.dumps(settings, indent=2))

Exceptions

When something goes wrong Python raises an exception. Handle the ones you expect:

try:
    quantity = int(input("Quantity: "))
except ValueError:
    print("Please enter a whole number.")
else:
    print(f"Ordering {quantity}")       # runs if no exception
finally:
    print("Done")                       # always runs
  • Catch specific exceptions. A bare except: hides real bugs, including typos.
  • Do not use exceptions to silence problems: log them or re-raise.

Raising your own

class InsufficientFunds(Exception):
    pass

def withdraw(balance, amount):
    if amount <= 0:
        raise ValueError("amount must be positive")
    if amount > balance:
        raise InsufficientFunds(f"balance {balance} < {amount}")
    return balance - amount

Reading a traceback

Read it from the bottom: the last line is the error type and message; the lines above show the call chain, with your file and line number. Most bugs are found within a minute by reading tracebacks carefully.

Logging instead of print

import logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger(__name__)
log.info("Imported %d users", len(users))
log.exception("Import failed")   # inside except: includes the traceback

Exercise

Write a script that reads orders.csv, skips rows with invalid numbers (logging a warning with the row number), and writes a summary.json with total revenue and order count.

Check yourself

  • Why use with open(...)?
  • What is wrong with a bare except:?
  • Which line of a traceback do you read first?

ההתקדמות שלכם נשמרת בדפדפן הזה בלבד.

שליחה לבדיקה (10 נקודות)