Подтвердить что ты не робот

Концепция интерфейса Duck typing и (java)

Я только что прочитал статью в Википедии о duck typing, и мне кажется, что я пропустил важный момент в концепции интерфейса, которую я использовал в Java:

"When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck."


class Duck:
    def quack(self):
        print("Quaaaaaack!")
    def feathers(self):
        print("The duck has white and gray feathers.")
    def swim(self):
        print("Swim seamlessly in the water")

class Person:
    def quack(self):
        print("The person imitates a duck.")
    def feathers(self):
        print("The person takes a feather from the ground and shows it.")
    def name(self):
        print("John Smith")

def in_the_forest(duck):
    duck.quack()
    duck.feathers()

def game():
    donald = Duck()
    john = Person()
    in_the_forest(donald)
    in_the_forest(john)

game()

что, если в in_the_forest я пишу:

  • это quack как утка? да
  • У него есть утка feathers? да
  • отлично, это утка у нас есть!

и позже, потому что я знаю, что это утка, я хочу, чтобы она была swim? john будет тонуть!

Я не хочу, чтобы мое приложение разбивалось (случайно) в середине своего процесса только потому, что Джон подделывался как утка, но я думаю, не было бы мудрой идеей проверять все атрибуты объекта, когда Я получаю его...?

4b9b3361

Ответ 1

Утиная печать на самом деле не связана с проверкой того, нужны ли вам вещи, а затем их использование. Утиная печать - это просто использование того, что вам нужно.

Функция in_the_forest была написана разработчиком, который думал о утках. Он был разработан для работы с Duck. A Duck может quack и feathers, поэтому кодер использовал эти функции, чтобы выполнить задание. В этом случае тот факт, что a Duck также может swim не использоваться и не нужен.

В статическом языке, таком как Java, in_the_forest было бы объявлено, чтобы взять Duck. Когда кодер позже обнаружил, что у них есть Person (который также мог бы quack и feathers) и хотел бы повторно использовать эту функцию, им не повезло. Является ли Person подкласс Duck? Нет, это совсем не подходит. Есть ли интерфейс QuacksAndFeathers? Может быть, если нам повезет. В противном случае нам нужно будет сделать один, перейдите в Duck, чтобы реализовать его, и измените in_the_forest, чтобы вместо Duck взять QuacksAndFeathers. Это может быть невозможно, если Duck находится во внешней библиотеке.

В Python вы просто передаете свой Person на in_the_forest, и он работает. Поскольку оказывается, что in_the_forest не нужен Duck, ему нужен только "утиный" объект, и в этом случае Person достаточно утка.

game, хотя нуждается в другом определении "утка", которое немного сильнее. Здесь Джон Смит не повезло.

Теперь верно, что Java поймал бы эту ошибку во время компиляции, а Python этого не сделает. Это можно рассматривать как недостаток. Аргумент счетчика про-динамической типизации заключается в том, что любой существенный кусок кода, который вы пишете, всегда будет содержать ошибки, которые может уловить компилятор no (и, честно говоря, Java даже не является особенно хорошим примером компилятора с сильными статическими проверками, чтобы поймать множество ошибок). Поэтому вам нужно проверить свой код, чтобы найти эти ошибки. И если вы тестируете эти ошибки, вы будете тривиально находить ошибки, в которых вы передали Person функции, которая нуждается в Duck. Учитывая, что динамический машинист говорит, язык, который соблазняет вас тестированием не, потому что он обнаруживает, что некоторые из ваших тривиальных ошибок на самом деле плохо. И, кроме того, это мешает вам делать некоторые действительно полезные вещи, например, повторно использовать функцию in_the_forest на Person.

Лично я разорван в двух направлениях. Мне очень нравится Python с гибкой динамической типизацией. И мне очень нравятся Haskell и Mercury для их мощных систем статического типа. Я не являюсь поклонником Java или С++; на мой взгляд, у них есть все плохие биты статического ввода с несколькими хорошими битами.

Ответ 2

Невозможно говорить для других языков, но в python недавно (v2.6) был представлен Модуль абстрактных базовых классов (ABC).

Если вы прочтете обоснование своего введения (PEP 3119), вы быстро поймете, что часть причины заключалась в том, чтобы "спасти Джона от уверенности" смерть "или, другими словами, чтобы облегчить проверку факта, когда вы программируете интерфейс, все методы интерфейса будут там. От связанного PEP:

ABC - это просто классы Python, которые добавляются в наследование объектов дерева, чтобы сигнализировать о некоторых особенностях это объект для внешнего инспектора. Тесты выполняются с использованием isinstance() и наличие конкретного ABC означает что тест прошел. К тому же, ABC определяют минимальный набор методы, которые характерное поведение типа. Код, который различает объекты на основе по своему типу ABC могут доверять тем, что эти методы всегда будут присутствовать.

В общем случае вы можете применить тот же шаблон для своего собственного кода. Например: вы можете создать класс BasePlugin со всеми методами, необходимыми для работы плагина, и затем вы можете создать несколько разных плагинов, выполнив их подклассификацию. В зависимости от того, должен ли каждый плагин определять или определять эти методы, вы можете определить методы BasePlugin для молчания (плагины могут определять эти методы) или повысить исключение (плагины должны определять эти методы/переопределять BasePlugin один).

РЕДАКТИРОВАТЬ: В потоке комментариев ниже мне было предложено включить в ответ этот бит обсуждения:

Этот вид функций - по крайней мере, на python - не реализован для человека-программиста (питон никогда не замалчивает ошибку, поэтому там уже много обратной связи), а скорее ради собственной возможности самоанализа python ( таким образом, легче писать динамическую загрузку, метапрограммирование кода и т.д.). Другими словами: я знаю, что Джон не может летать... но я хочу, чтобы интерпретатор python знал об этом!:)

Ответ 3

Я не хочу, чтобы мое приложение разбивалось (случайно) в середине своего процесса только потому, что Джон подделывался как утка, но я думаю, не было бы мудрой идеей проверять все атрибуты объекта, когда Я получаю его...?

Это проблема динамической типизации в целом. На статически типизированном языке, таком как Java, компилятор проверяет время компиляции, если Person реализует IDuck или нет. На динамически типизированном языке, таком как Python, вы получаете ошибку во время выполнения, если Person пропускает определенную функцию утки (например, swim). Чтобы процитировать другую статью в Википедии ( "Тип системы" , раздел "Динамический ввод" ):

Динамическое типирование может привести к ошибкам типа времени выполнения, то есть во время выполнения значение может иметь неожиданный тип, и применяется операция, не имеющая смысла для этого типа. Такие ошибки могут возникнуть долго после того, как была допущена ошибка программирования, то есть место, где неверный тип данных передавался в место, которое он не должен иметь. Это может затруднить поиск ошибки.

Динамическая типизация имеет свои недостатки (вы упомянули одно) и ее преимущества. Краткое сравнение можно найти в другом разделе статьи системы Типа в Википедии: Статическая и динамическая проверка типов на практике.