Что такое утиная типизация?
Что проверяют
Знаете ли вы, что интерфейс объекта в Python задаётся набором методов, а не классом, и можете ли назвать конкретные протоколы языка. Это вход в разговор про абстрактные базовые классы, typing.Protocol и стиль EAFP, поэтому ответ уровня «ходит как утка» засчитывают редко.
Как отвечать
Если объект поддерживает нужные операции, он подходит: len() работает с чем угодно, где определён __len__, цикл for с чем угодно, где есть __iter__, менеджер контекста с объектом, у которого есть __enter__ и __exit__. Наследоваться от конкретного класса не требуется.
Дальше покажите границы механизма. Дандер-методы ищутся на типе, а не на экземпляре: присвоенный экземпляру __len__ не заработает. Проверять поведение принято в стиле EAFP, то есть пробовать и ловить исключение, а не опрашивать hasattr заранее.
Статически то же самое описывает протокол: структурный интерфейс, наследовать который классу не нужно.
from typing import Protocol
class Sized(Protocol):
def __len__(self) -> int: ...
def is_empty(obj: Sized) -> bool:
return len(obj) == 0С декоратором runtime_checkable такой протокол работает и в isinstance, но сверяются только имена методов, а не сигнатуры.
Где спотыкаются
Сводят ответ к байке про утку и не называют ни одного дандер-метода. Вопрос ровно про них, а птица нужна была автору термина, а не интервьюеру.
Пишут type(obj) == list или длинные цепочки isinstance, отсекая собственные совместимые типы: кортеж, генератор, любой объект с __iter__.
Считают, что аннотации проверяются при выполнении. Интерпретатор их не сверяет, аннотация это материал для проверяющего инструмента, а в рантайме остаётся та же утиная типизация со всеми падениями на месте вызова.