A generic Stack, bounds and constraints
Stack[int] is a hint only: the string still goes in at run time. Constraints and bounds are stored on the type variable.
A generic function or class works for many types while keeping track of which: first([1, 2]) gives an int, first(['a']) gives a str. You declare the placeholder with TypeVar or, since Python 3.12, with the clean def f[T](x: T) and class Box[T] syntax.
Change the code and press Run (Ctrl+Enter). Predict what will happen first, then break it on purpose and read what changes. Your edits are saved and match the lesson page.
Ready for more? This phase has 5 hands-on exercises with automatic checks.
Practice questions
Write the code in the editor, run it, then open the model answer to compare.
Write last[T](items: Sequence[T]) -> T and print last([1, 2, 3]) and last("hey").
Write class Pair[A, B] holding two values, with a method swap() returning a Pair[B, A], and print the swapped pair's items.
Write type Matrix = list[list[float]] and a function that returns the sum of every number in it.
Explain it without notes
What problem does a type variable solve?
What is the difference between a bound and constraints on a type variable?
Does Stack[int]() stop you pushing a string at run time? Why or why not?
How do the 3.12 generic syntax and TypeVar differ?
Explain variance: why is list[Dog] not a list[Animal], and what is the 3.12 syntax's advantage there?
Expected output
2 1
class without [int]: <class '__main__.Stack'> | with: __main__.Stack[int]
items now: [1, 'oops']
9 2.5 coffee
constraints: (<class 'int'>, <class 'float'>)
bound: <class 'str'>
old style bound: typing.Hashable