What are Abstract Base Classes in Python, how do you define them, and how do they relate to duck typing?
Abstract Base Classes (ABCs) from the `abc` module let you declare interfaces with `@abstractmethod` — any concrete subclass that does not implement all abstract methods raises `TypeError` at instantiation. ABCs coexist with duck typing: you can register unrelated classes as virtual subclasses without inheritance, and `isinstance` checks will pass.
How to think about it
The question is really asking: how do you enforce a contract in Python without reaching for a statically-typed language? Duck typing is flexible but silent — you only find out at runtime that a method is missing, at the worst possible moment. ABCs give you that safety net at instantiation time instead.
What’s really being tested
Interviewers want to see that you understand the tension between Python’s flexibility and production-code reliability. ABCs are the answer when you’re designing a plugin system, a data-source abstraction, or any place where multiple teams will implement the same interface.
Step 1 — Understand the protocol
ABC is just a base class that uses ABCMeta as its metaclass. The @abstractmethod decorator marks methods that subclasses must implement. If they don’t, Python refuses to instantiate the class — the error fires at ClassName(), not buried inside some method call three levels deep.
Step 2 — Define the interface
Think of the ABC as a contract document. You are saying: “anything that calls itself a DataSource must be able to read() and close().”
Step 3 — Implement concrete classes
Concrete subclasses inherit from the ABC and fill in every abstract method. Miss one, and you get TypeError the moment someone tries to create an instance.
Step 4 — Virtual subclasses for legacy code
register() lets you tell an ABC “trust me, this old class also satisfies the interface” — isinstance will return True without inheritance. This is how Python’s own collections.abc types work: list is recognised as a Sequence without literally inheriting from it.
The key insight — why this works
Python’s metaclass ABCMeta tracks which methods are still abstract in a class. When you call IncompleteSource(), the metaclass checks whether any abstract methods remain unimplemented and raises TypeError before __init__ even runs. This is a class-creation-time check, not a runtime attribute lookup.
__subclasshook__ — structural matching
For truly duck-typed checks, override __subclasshook__ to make isinstance pass automatically whenever required attributes are present, no registration needed:
class Readable(ABC):
@classmethod
def __subclasshook__(cls, subclass: type) -> bool:
if cls is Readable:
return hasattr(subclass, "read") and callable(subclass.read)
return NotImplemented