Checkpoint: The Standard Library
A checkpoint is a hands-on review where you combine several standard-library modules — functools, enums, namedtuple, hashlib, and more — into one small working tool.
Learn Checkpoint: The Standard Library in our free Python course — an interactive lesson with runnable examples, a practice exercise and a quick reference.
Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
You have learned a lot of powerful modules. This is where they stop being separate lessons and start being a toolkit you reach into to solve a real problem.
@lru_cache memoizes pure functions; partial pre-fills arguments; reduce folds a sequence; @wraps preserves a decorated function's name.
Group fixed choices as named members with .name and .value ; iterate them; use IntEnum for ordered comparisons.
Immutable records with named fields; copy with _replace ; the typing.NamedTuple class form adds defaults and methods.
sha256(...).hexdigest() fingerprints data; encode strings first; hashing is one-way, and passwords need a salted KDF.
Build a tiny order-processing tool, one step at a time, using four modules together:
Compute the tax-inclusive total of the billable orders (status PAID or SHIPPED), then hash a short report of the result. Start from the runnable scaffold below:
Extend the idea: model tasks with an IntEnum priority and a namedtuple, then sum a cached cost over the high-priority tasks and fingerprint the summary. This reuses the same four-module pattern on fresh data.
Answer each from memory, then expand to check yourself.
1. What does @lru_cache require of a function's arguments, and why?
They must be hashable (e.g. numbers, strings, tuples — not lists or dicts), because the cache stores results in a dictionary keyed by the arguments. Passing a list raises TypeError: unhashable type: 'list' .
2. Why is Color.RED == 1 False for a plain Enum , and how do you change that?
A plain Enum member is its own object, not its raw value — that is a safety feature. If you genuinely need members to compare equal to integers, subclass IntEnum instead, where Priority.MEDIUM == 2 is True .
3. How do you "change" a field on a namedtuple?
You cannot mutate it — it is immutable. You build a new copy with _replace : p = p._replace(x=10) . The original is untouched, so remember to assign the result back.
4. Why must you call .encode() before hashing a string with hashlib?
Hash functions operate on bytes , not text. A str must be encoded (almost always UTF-8) first: hashlib.sha256("hi".encode("utf-8")) . Forgetting raises "Unicode-objects must be encoded before hashing."
5. Why is passing a list of arguments safer than shell=True in subprocess?
With a list, each element is treated as one literal argument, so user input can never be reinterpreted as extra shell commands. shell=True hands a string to a shell to parse, which is the classic command-injection risk when any part of that string is untrusted.
6. Do type hints raise a TypeError at runtime when an argument's type is wrong?
No. Python ignores hints while running — double("ab") on a function annotated -> int just runs. Hints are checked by static tools like mypy and by your editor, not the interpreter.
Bookmark the modules you used in this checkpoint:
Checkpoint complete — the standard library is your toolkit now!
You combined an enum, a namedtuple, an lru_cache 'd computation, and a sha256 fingerprint into one working tool — and verified it with a unittest. That is exactly how these modules are used together in real software.
🚀 Up next: Final Project — bring the whole course together in one capstone build.
Practice quiz
What does @lru_cache require of a function's arguments, and why?
- They must be integers, because the cache uses array indexes
- They must be immutable strings only
- They must be hashable, because results are stored in a dict keyed by the arguments
- They must be positional, not keyword
Answer: They must be hashable, because results are stored in a dict keyed by the arguments. lru_cache stores results in a dictionary keyed by the arguments, so they must be hashable. Passing a list raises TypeError: unhashable type: list.
For a plain Enum, why is Color.RED == 1 False, and how do you change it?
- A plain Enum member is its own object, not its raw value — subclass IntEnum to compare equal to ints
- It is a bug; use .value to compare
- Enums never support ==
- Use str(Color.RED) instead
Answer: A plain Enum member is its own object, not its raw value — subclass IntEnum to compare equal to ints. A plain Enum member is a distinct object, not its raw value — a safety feature. IntEnum members compare equal to their integer values.
How do you "change" a field on a namedtuple?
- Assign directly: p.x = 10
- Call p.set("x", 10)
- Convert to a list, edit, convert back
- Use p._replace(x=10), which returns a new copy
Answer: Use p._replace(x=10), which returns a new copy. Namedtuples are immutable. _replace returns a new copy with the changed field; the original is untouched, so assign the result back.
Why must you call .encode() before hashing a string with hashlib?
- To make the hash shorter
- Hash functions operate on bytes, not text, so the str must be encoded first
- Because sha256 is case-sensitive
- To add a salt automatically
Answer: Hash functions operate on bytes, not text, so the str must be encoded first. Hash functions work on bytes. A str must be encoded (almost always UTF-8) first, or Python raises "Unicode-objects must be encoded before hashing."
Why is passing a list of arguments safer than shell=True in subprocess?
- Each list element is a literal argument, so input cannot be reinterpreted as shell commands
- Lists run faster
- shell=True is deprecated
- Lists allow piping
Answer: Each list element is a literal argument, so input cannot be reinterpreted as shell commands. With a list, each element is one literal argument and cannot become extra shell commands. shell=True hands a string to a shell to parse — the classic injection risk.
Do type hints raise a TypeError at runtime when an argument has the wrong type?
- Yes, always
- Yes, but only for return types
- No — Python ignores hints at runtime; static tools like mypy check them
- Only when assertions are enabled
Answer: No — Python ignores hints at runtime; static tools like mypy check them. Python ignores annotations while running. Hints are validated by static checkers like mypy and your editor, not the interpreter.
What does functools.partial do?
- Splits a function into smaller functions
- Pre-fills some arguments, returning a new callable that takes the rest
- Caches the function results
- Runs the function partially then pauses
Answer: Pre-fills some arguments, returning a new callable that takes the rest. partial pre-binds arguments to a function and returns a new callable that only needs the remaining ones.
What does functools.reduce do over a sequence?
- Removes duplicate items
- Filters out falsy items
- Returns the shortest element
- Folds the sequence into a single value by applying a function cumulatively
Answer: Folds the sequence into a single value by applying a function cumulatively. reduce applies a two-argument function cumulatively across the items, folding them into one final value.
In the order-summary build, which orders are counted as billable?
- Only NEW orders
- Orders with status PAID or SHIPPED
- All orders regardless of status
- Only orders above a price threshold
Answer: Orders with status PAID or SHIPPED. The tool keeps orders whose status is PAID or SHIPPED, then sums their tax-inclusive amounts.
Why does the build challenge fingerprint the report string with sha256?
- To compress the report
- To encrypt the data so it cannot be read
- So any change to the result is detectable via a stable digest
- To sort the orders
Answer: So any change to the result is detectable via a stable digest. A sha256 digest is a fingerprint of the exact report text; if the result changes, the digest changes, making tampering or drift detectable.