«Код против интерфейса, а не объекта» не имеет буквального смысла в Python, потому что язык не имеет функции интерфейса. Эквивалент грубый Python - это «использовать утку». Если вы хотите увидеть, является ли объект уткой, другими словами, вы должны проверить, есть ли у него метод quack()
, или, что еще лучше, попытаться quack()
и обеспечить соответствующую обработку ошибок, а не проверять, если он является экземпляром Duck
.
Обычными типами уток в Python являются файлы (ну, на самом деле, файловые объекты), отображения (dict
-подобные объекты), вызываемые объекты (функционально-подобные объекты), последовательности (list
-подобные объекты) и итерируемые (вещи, которые вы можете перебирать, которые могут быть контейнерами или генераторами).
В качестве примера, функции Python, которым нужен файл, обычно будут рады принять объект, реализующий методы file
, в которых он нуждается; он не должен быть производным от класса file
. Например, чтобы использовать объект в качестве стандартного, главное, что ему понадобится, - это метод write()
(и, возможно, flush()
и close()
, который на самом деле ничего не должен делать). Аналогично, вызываемый объект - это любой объект, имеющий метод __call__()
; он не должен быть получен из типа функции (фактически, вы не можете получить из типа функции).
Вы должны принять аналогичный подход. Проверьте методы и атрибуты, которые вам нужны для того, что вы собираетесь делать с объектом. А еще лучше, документируйте то, что вы ожидаете, и предполагайте, что тот, кто вызывает ваш код, не является полной глупостью. (Если они дадут вам объект, который вы не можете использовать, они наверняка поймут это достаточно быстро из ошибок, которые они получают.) Проверяйте для определенных типов только при необходимости. иногда необходимо, поэтому Python дает вам type()
, isinstance()
и issubclass()
, но будьте осторожны с ними.
Печатание уток в Python эквивалентно «коду против интерфейса, а не по объекту» в том смысле, что вам советуют не делать свой код слишком зависимым от типа объекта, а скорее видеть, имеет ли он нужный вам интерфейс , Разница в том, что в Python «интерфейс» означает неформальный набор атрибутов и методов объекта, которые обеспечивают определенное поведение, а не языковую конструкцию, специально названную interface
.
Вы можете до некоторой степени формализовать Python-интерфейсы, используя модуль abc
, который позволяет вам объявить, что данный класс является подклассом данного «абстрактного базового класса» (интерфейса), используя любые критерии, которые вы пожелаете, например, так как «он имеет атрибуты color
, tail_length
и quack
, а quack
может вызываться». Но это все же намного менее строго, чем статические языки, имеющие функцию интерфейса.