Утиная типизация = динамическая типизация?
Не могу найти явный ответ. Утиная типизация это тоже самое, что динамическая типизация, это лишь один из вариантов динамической типизации или что-то третье?
Ответы (1 шт):
Давайте разберемся по-порядку.
Динамическая типизация означает, что вам не нужно явно определять тип переменной на этапе написания кода, интерпретатор попытается самостоятельно определить тип этой переменной во время исполнения программы (динамически) исходя из его значения.
Утиная типизация означает, что для работы программы нам важен не сам тип объекта, а его функциональная составляющая. То есть, если некий объект содержит в себе необходимые атрибуты и методы, то это означает, что он удовлетворяет нашим требованиям.
Отсюда известная фраза:
Если нечто выглядит как утка, плавает как утка и крякает как утка, то это, вероятно, и есть утка.
Другими словами, за утку мы считаем что угодно, что умеет плавать как утка и крякать как утка, и, хотя, на самом деле это может оказаться совсем не утка, а какой-нибудь гусь, нас это не должно волновать, поскольку для нашей задачи объект реализует весь необходимый функционал.
Не могу не вставить потрясающую картинку, которая прекрасным образом иллюстрирует вышесказанное :)
Приведу простой пример утиной типизации:
В языке Python есть функция str() для перевода объекта в строку :
type(1) -> <class 'int'>
type(str(1)) -> <class 'str'>
Как она на самом деле работает? Если упростить, то это выглядит примерно следующим образом:
def str(obj):
return obj.__str__
"Под капотом" вызывается "магический" метод __str__, который и реализует требуемый функционал.
Но тут есть нюанс, если мы напишем так:
class A:
...
a = A()
str(a) # <__main__.A object at 0x0000019E62D27C10>
То, никакой ошибки не возникнет, хочется спросить - почему? Ведь класс A не реализует магический метод __str__.
Тут дело в том, что все объекты в языке Python по умолчанию наследуются от базового класса object, а сам класс object в свою очередь уже реализует магический метод __str__, поэтому требуемое поведение будет взято из базового класса.
Суть этого примера в том, чтобы показать - функции str() не важно объект какого типа вы передадите ей в качестве аргумента, главное, чтобы этот объект умел конвертироваться в строку (реализовывал магический метод __str__).
Но object, конечно же, реализует не все магические методы и если написать, например:
class A:
...
a = A()
b = A()
print(a + b)
То тут мы уже получим исключение TypeError: unsupported operand type(s) for +: 'A' and 'A', поскольку ни класс A, ни базовый класс object не реализуют магический метод для сложения объектов __add__.
Динамическая и утиная типизация - это одно и то же?
И хотя утиная типизация используется в основном в динамически типизированных языках, существуют примеры и статической утиной типизации - это, например, шаблоны С++:
template <typename T>
void f(T x) { x.foo(); }
В этой функции есть ограничение только на тип переменной, но нет ограничения на то, что объект этого типа должен реализовывать метод foo(), но это будет проверено во время компиляции (а не динамически).
Также, несмотря на то, что все динамически типизированные ООП языки поддерживают утиную типизацию можно придумать пример (почти бесполезный в практике), когда язык будет динамически типизированным, но без утиной типизации: например, PHP с ограничением на базовые типы, без использования ООП.
Какой вывод?
Утиная типизация это тоже самое, что динамическая типизация, это лишь один из вариантов динамической типизации или что-то третье?
Динамическая типизация и утиная типизация - это не одно и то же и они не являются вариантами друг друга, а вполне могут существовать по отдельности.
Динамическая типизация - это функциональность языка, при который типы переменных вычисляются динамически на этапе выполнения программы.
Утиная типизация полагается на реализацию объектом необходимых методов, а тип самого объекта не проверяется.
