We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Orientation and the Gate step 9 of 13
Placement 2/6: Protocol vs ABC
Placement diagnostic, 2 of 6. About seven minutes. No worked example — if this one is opaque, T2 (Structural Typing and the Hard Parts) is where you start.
An ABC is nominal: Duck implements it because Duck inherits from it.
A Protocol is structural: Duck implements it because Duck happens to
have the right methods, whether or not Duck has ever heard of the protocol.
That difference decides who is allowed to satisfy your interface. An ABC
cannot be satisfied by a class you do not own — a third-party type, a stdlib
type, a mock. A Protocol can.
The module gives you three unrelated classes and a registry mapping names to
them. Duck and Robot both have speak() -> str. Rock has roll() and
no speak. None of them inherits from anything.
Write:
def solve(order: list[str]) -> list[str]:
For each name in order, in order:
-
unknown name →
"<unknown>" -
the constructed object satisfies
Speaker→ the result ofspeak() -
otherwise →
"<silent>"
Names are case-sensitive: "Duck" is not "duck".
Three things this measures
@runtime_checkable. isinstance(obj, SomeProtocol) raises TypeError
at runtime unless the protocol carries that decorator, and mypy separately
reports Only @runtime_checkable protocols can be used with instance and class checks [misc]. The starter deliberately omits it.
What isinstance on a protocol actually checks. Presence of the named
attributes, and nothing else. Not signatures, not parameter types, not
return types. A class with speak = 42 passes isinstance(obj, Speaker)
while obj.speak() raises TypeError. @runtime_checkable is a cheap
smoke test, not interface validation — the real validation is the static
check mypy performs at every call site.
Why not hasattr. if hasattr(obj, "speak"): obj.speak() also runs, and
also type-checks — because mypy narrows a hasattr to give the attribute
type Any. obj.speak(1, 2, 3, "garbage") type-checks too. You have
written code that looks defensive and has silently opted out of checking.
The Protocol narrows object to Speaker, so obj.speak() is known to
return str and a wrong call is a compile error.
Production consequence
This is the seam question. If your Storage interface is an ABC, every test
double must subclass it and every third-party adapter needs a wrapper. If it
is a Protocol, unittest.mock.MagicMock, an in-memory dict, and the real S3
client can all satisfy it without a single import pointing from the
implementations back at your interface — which is the actual definition of a
dependency inversion.
Loading visualization…
Stuck?
Python reference solution
Sign in to attempt this problem and reveal the reference solution.