We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Interfaces with Protocols and ABCs step 7 of 26
Type a Handler Registry with a Callback Protocol
A registry maps names to text handlers. Each handler takes a string and an
optional keyword argument retries, and returns a string. The starter types
the registry as dict[str, Callable[..., Any]]. The ... accepts any
arguments and Any turns off checking of the result, so mypy cannot catch a
handler with the wrong shape.
Describe the handler with a callback protocol
Callable[[str, int], str] lists positional parameters only. It cannot say
that retries is a keyword argument, or that callers may leave it out. A
callback protocol can. It is a protocol with a __call__ method, so it
describes how you call an object:
class Handler(Protocol):
def __call__(self, payload: str, /, *, retries: int = 0) -> str: ...
The / makes payload positional-only, and the * makes retries
keyword-only. The = 0 tells mypy that callers may leave retries out. A
plain function fits Handler when it accepts the same calls, without
inheriting from anything.
With dict[str, Handler], mypy rejects a handler that names its keyword
retry, one that requires retries, and one that returns bytes.
What to write
Declare Handler.__call__ as above, and change the annotation to
REGISTRY: dict[str, Handler]. Keep the three handler signatures from the
starter, including /, * and the default of 0, and fill in their bodies:
| Key | Returns |
|---|---|
shout |
payload.upper() + "!" * retries |
tag |
f"[{retries}]{payload}" |
trim |
payload.strip() * (retries + 1) |
shout("ab", retries=2) # "AB!!"
tag("x") # "[0]x"
trim(" hi ", retries=1) # "hihi"
shout("z", retries=-1) # "Z"
trim("x", retries=-1) # ""
Do not clamp a negative retries. A string times zero or a negative number
is "", and the tests expect that. The handlers retry nothing. Here retries
only changes the formatting.
dispatch(name, payload, retries) -> str looks up name in REGISTRY. The
keys are case-sensitive. If name is missing, return f"unknown:{name}".
Otherwise call the handler once, as handler(payload, retries=retries), and
return its result. Let any exception from a handler propagate.
solve(names, payloads, retries) -> list[str] walks the three lists together
with zip(..., strict=True) and dispatches each triple in order. Three empty
lists give [], and lists of different lengths raise ValueError.
solve(["tag", "Shout", "trim"], ["x", "y", " z "], [2, 0, 0])
# ["[2]x", "unknown:Shout", "z"]
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Python reference solution
Sign in to track your attempts toward unlocking the reference solution.