Abstract Base Classes & Protocols Interview Questions & Answers

5 questions Updated 2026-06-18

Python interview questions on abstract base classes and @abstractmethod, why use ABCs, collections.abc, duck typing vs ABCs, and typing.Protocol for structural/static duck typing with runtime_checkable.

An abstract base class (ABC) is a class that can't be instantiated directly and defines a set of methods subclasses must implement. You build one by subclassing abc.ABC and decorating required methods with @abstractmethod. Python refuses to instantiate any subclass that leaves an abstract method unimplemented.

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):            # subclasses MUST implement this
        ...

Shape()                        # TypeError — can't instantiate abstract class

class Circle(Shape):
    def __init__(self, r):
        self.r = r
    def area(self):            # concrete implementation
        return 3.14159 * self.r ** 2

Circle(2).area()               # 12.566... — works

@abstractmethod turns the "must implement" contract into an enforced, load-time check rather than a runtime NotImplementedError later. It defines an interface that subclasses are required to fulfill.

ABCs enforce an interface — they guarantee at instantiation time that subclasses provide the required methods, catching mistakes early instead of blowing up deep in your code. They also document intent clearly and integrate with isinstance checks, so callers can verify capabilities.

from abc import ABC, abstractmethod

class Storage(ABC):
    @abstractmethod
    def save(self, key, value): ...
    @abstractmethod
    def load(self, key): ...

class FileStorage(Storage):
    def save(self, key, value): ...
    # forgot load() ...

FileStorage()      # TypeError — flags the missing method immediately
isinstance(FileStorage, type) and issubclass(FileStorage, Storage)  # True

Use an ABC when you have a family of classes that must share a contract and you want that contract enforced. For looser, optional interfaces, plain duck typing or a Protocol may fit better.

collections.abc provides the standard ABCs for Python's container protocolsIterable, Iterator, Sequence, Mapping, Hashable, and more. You use them two ways: as a base class to inherit mixin methods, and in isinstance checks to test whether an object supports a protocol.

from collections.abc import Iterable, Sequence, Mapping

isinstance([1, 2], Iterable)   # True
isinstance("abc", Sequence)    # True
isinstance({}, Mapping)        # True

class MyList(Sequence):        # inherit the protocol's mixin methods
    def __init__(self, data):
        self._data = data
    def __getitem__(self, i):
        return self._data[i]
    def __len__(self):
        return len(self._data)
    # get __contains__, __iter__, __reversed__, index, count for FREE

Subclassing Sequence and implementing just __getitem__ + __len__ gives you a fully functional sequence. Prefer these standard ABCs over inventing your own for container-like types.

Duck typing is "if it walks like a duck and quacks like a duck, it's a duck" — Python doesn't check the type, it just tries the operation and works if the needed methods exist. ABCs add an explicit, enforced contract on top, letting you assert membership and catch missing methods up front.

# Duck typing — no declared interface, just call and hope:
def make_it_quack(thing):
    thing.quack()          # works for ANYTHING with a quack() method

class Dog:
    def quack(self): return "woof-quack"
make_it_quack(Dog())       # works — Dog "is" a duck here

# ABC — explicit, checkable contract:
from abc import ABC, abstractmethod
class Duck(ABC):
    @abstractmethod
    def quack(self): ...

Duck typing is flexible and Pythonic but defers errors to runtime; ABCs trade some flexibility for early enforcement and clear interfaces. Use duck typing for loose coupling, ABCs when you want guarantees.

typing.Protocol enables structural typing ("static duck typing"): a class satisfies a protocol simply by having the right methods/attributes — no explicit inheritance needed. Type checkers verify the structure statically, giving you duck typing's flexibility with static safety. Add @runtime_checkable to also allow isinstance checks at runtime.

from typing import Protocol, runtime_checkable

@runtime_checkable
class Drawable(Protocol):
    def draw(self) -> str: ...     # required shape, not inheritance

class Button:                      # does NOT inherit Drawable
    def draw(self) -> str:
        return "[Button]"

def render(item: Drawable) -> str: # type checker accepts Button
    return item.draw()

render(Button())                   # works — structural match
isinstance(Button(), Drawable)     # True — thanks to @runtime_checkable

Unlike ABCs, classes don't register or subclass anything — matching the structure is enough. Note @runtime_checkable only checks method names/existence, not signatures. Use Protocols for flexible, statically verified interfaces; use ABCs when you need shared implementation or explicit registration.

Practice tests are coming soon

Get notified when interactive mock interviews and quizzes launch.