Type hints: saying what a value should be
The dataclass in lesson 21 had id: int in it. Those annotations work on functions too, and they are how frameworks learn what your code expects.
def cost(tokens: int, price_per_1000: float = 0.15) -> float:
return round(tokens / 1000 * price_per_1000, 4)
print(cost(1200))tokens: int says tokens should be an int. -> float says what the function returns. The code runs exactly as it did in lesson 12; the hints are for people, editors, and tools that read them.
Python does not check them
print(cost("1200"))Python ran the function with a string, and it failed on the division inside, not at the call. An editor with type checking would underline cost("1200") before you run anything, which is the practical reason to write hints.
Lists, dictionaries and maybe-nothing
def find_customer(tickets: list[dict], ticket_id: int) -> str | None:
for ticket in tickets:
if ticket["id"] == ticket_id:
return ticket["customer"]
return None
tickets = [{"id": 1, "customer": "Asha"}, {"id": 2, "customer": "Ben"}]
print(find_customer(tickets, 2))
print(find_customer(tickets, 9))list[dict] is a list of dictionaries. str | None means a string or nothing, and warns whoever calls it to handle the None.
Why frameworks care: a function given to an agent as a tool is read, hints and all, to tell the model what arguments the tool takes. A missing hint is missing information for the model.
Reading the hints from code
print(cost.__annotations__)Hints are stored on the function, and any code can read them. That is all a framework does when it turns your function into a tool description.
- Add hints to
categorisefrom lesson 11. - Print
find_customer.__annotations__. - Change
-> str | Noneto-> strand run it. Does anything change?
Slow is fine. Stopping is the only problem.