Learning bite
Types, functions, and exceptions
Build a small automation function with explicit inputs and failures.
On this page
Turn a manual decision into a program
Suppose a supplied capacity report says a disk has 20 GiB total and 8 GiB used. A person subtracts, checks that the values make sense, and reports 12 GiB remaining. Python lets us make those steps explicit and repeat them for many reports. These are invented inputs; the program does not inspect your disk.
Work in the capacity-tool directory from the setup lesson with its virtual environment active. In Python, = binds a name to a value; == compares two values. Numbers such as 20 are integers, 0.5 is a float, "20" is a string, and True/False are booleans. None represents an absent value. A string containing digits is still text until you convert it.
Save and run values.py:
total = 20
used = 8
remaining = total - used
print(remaining)
print(remaining > 5)
print(int("20") - used)
print("20" + "8")
Expected lines: 12, True, 12, and 208. The last operation joins text. int("twenty") raises ValueError; conversion is a decision about acceptable input, not an automatic repair.
Collections, decisions, and repetition
A list holds ordered items. A dictionary maps keys to values. Access a dictionary value by its key, rather than assuming it has a meaningful position:
samples = [{"name": "api", "total": 20, "used": 8},
{"name": "worker", "total": 10, "used": 9}]
for sample in samples:
available = sample["total"] - sample["used"]
if available < 3:
label = "review"
else:
label = "enough for this fixture"
print(f'{sample["name"]}: {available} GiB, {label}')
Add this below values.py and run it. Expected final lines: api: 12 GiB, enough for this fixture and worker: 1 GiB, review. Indentation groups statements into the loop and branches. for visits each item; if chooses a branch. An f-string inserts expressions into text. This threshold is our exercise rule, not a universal capacity recommendation.
Lists and dictionaries are mutable: their contents can change. Two names can refer to the same collection, so changing it through one name can affect the other. Avoid changing the list you are currently iterating over until you understand those effects.
Extract one responsibility
Save this as capacity.py:
def remaining_gib(total: int, used: int) -> int:
if type(total) is not int or type(used) is not int:
raise TypeError("capacity values must be integers")
if total < 0 or used < 0 or used > total:
raise ValueError("require 0 <= used <= total")
return total - used
if __name__ == "__main__":
samples = [{"total": 20, "used": 8}, {"total": 20, "used": 25}]
for sample in samples:
try:
print(remaining_gib(**sample))
except (TypeError, ValueError) as error:
print(f"invalid sample: {error}")
def creates a function. Parameters receive the caller's inputs; return gives a result back. Type hints document the intended types but do not enforce them. The explicit checks do. **sample supplies dictionary entries as named arguments, equivalent here to remaining_gib(total=20, used=8).
An exception interrupts normal execution. raise reports the reason; a matching except decides how to handle it. try covers the operation expected to fail. Catching every exception would also hide programming errors you have not accounted for. The exact type check rejects booleans because Python otherwise treats them as integer subclasses.
Run python capacity.py. Expect 12, followed by invalid sample: require 0 <= used <= total. The caller prints; the function only calculates or raises. That separation makes the calculation straightforward to test.
Try changes and explain them
Predict remaining_gib(20, -1), remaining_gib("20", 8), and remaining_gib(0, 0). They produce ValueError, TypeError, and 0, respectively. Zero is a valid result, so treating every false-like value as an error would be a bug.
Add a third valid sample and predict its output before running. Then import remaining_gib from another file: the example loop should stay quiet because of the main guard. Keep capacity.py; the next lesson supplies its inputs from a file.
References: Python introduction↗, control flow and functions↗, data structures↗, and exceptions↗.
Additional primary references: Functions↗.
Your notes and evidence
Record observations, questions, or links to your work. Keep credentials out of your notes.
Back up or restore this path
Progress and notes stay in this browser. A backup contains only this learning path.