Что такое утиная печать?

Я столкнулся с термином "утка", читающим случайные темы в онлайн-программном обеспечении и не полностью понимая его.

Что такое "утиная печать"?

Ответ 1

Это термин, используемый в динамических языках, у которых нет сильной печати.

Идея состоит в том, что вам не нужен тип, чтобы вызывать существующий метод для объекта - если на нем определен метод, вы можете его вызвать.

Название происходит от фразы "Если это выглядит как утка и шарлатан, как утка, это утка".

Wikipedia имеет гораздо больше информации.

Ответ 2

Утиная печать означает, что операция не формально указывает требования, которые должны соответствовать ее операндам, но только пытается выполнить с тем, что дано.

В отличие от других, это не обязательно связано с динамическими языками или проблемами наследования.

Пример задачи: Вызовите метод Quack для объекта.

Без использования утиного ввода функция f, выполняющая эту задачу, должна заранее указать, что ее аргумент должен поддерживать некоторый метод Quack. Общим способом является использование интерфейсов

interface IQuack { 
    void Quack();
}

void f(IQuack x) { 
    x.Quack(); 
}

Вызов f(42) завершается с ошибкой, но f(donald) работает до тех пор, пока donald является экземпляром IQuack -subtype.

Другим подходом является структурная типизация - но опять же метод Quack() формально задает все, что не может доказать его Quack заранее приведет к сбою компилятора.

def f(x : { def Quack() : Unit }) = x.Quack() 

Мы могли бы даже написать

f :: Quackable a => a -> IO ()
f = quack

в Haskell, где Quackable typeclass гарантирует существование нашего метода.


Итак, как утка набирать меняет это?

Ну, как я уже сказал, утиная система ввода не задает требований, а просто пытается, если что-то работает.

Таким образом, система динамического типа, как Python, всегда использует утиную печать:

def f(x):
    x.Quack()

Если f получает x, поддерживающий Quack(), все в порядке, если нет, то он будет аварийно завершен во время выполнения.

Но утиная печать не подразумевает динамическую типизацию вообще - на самом деле существует очень популярный, но полностью статический подход к набору уток, который тоже не дает никаких требований:

template <typename T>
void f(T x) { x.Quack(); } 

Функция ничего не говорит о том, что она хочет x, которая может Quack, поэтому вместо этого она просто пытается во время компиляции, и если все работает, это нормально.

Ответ 3

Простое объяснение (без кода)

Обсуждение семантики вопроса довольно нюансное (и очень академическое), но здесь общая идея:

Печатание утки

("Если он ходит как утка и крякает как утка, значит, это утка".) - ДА! Но что это значит??! Это лучше всего иллюстрируется на примере:

Пример: динамически типизированные языки

Представь, что у меня есть волшебная палочка. У него есть особые полномочия. Если я взмахну палочкой и скажу "Езжай!" машине, тогда она едет!

Работает ли это на других вещах? Не уверен: поэтому я пробую это на грузовике. Ух ты - это тоже диски! Затем я пробую это на самолетах, поездах и 1 Вудсе (это тип гольф-клуба, который люди используют, чтобы "водить" мяч для гольфа). Они все ездят!

Но будет ли это работать, скажем, чашка? Ошибка: KAAAA-BOOOOOOM! это не сработало так хорошо. ====> Чашки не могут водить! Дух !?

Это в основном концепция утки. Это система "попробуй перед покупкой". Если это работает, все хорошо. Но если это не удастся, ну, это взорвется на вашем лице.

Другими словами, нас интересует, что может сделать объект, а не то, чем он является.

Пример: статически типизированные языки

Если нас интересовало, что это за объект на самом деле, то наш магический трюк будет работать только на заранее заданных, разрешенных типах - в данном случае автомобилях, но не будет работать на других объектах, которые могут ездить: грузовиках, мопедах, тук-туках и т.д. Он не будет работать на грузовиках, потому что наша волшебная палочка ожидает, что он будет работать только на автомобилях.

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

Единственный способ заставить грузовик ехать, если вы каким-то образом можете заставить волшебную палочку рассчитывать как на грузовики, так и на автомобили (возможно, путем "реализации общего интерфейса"). Если вы не знаете, что это значит, просто проигнорируйте это.

Краткое описание: вынос ключа

Что важно при наборе утки, это , что объект может на самом деле делать, а не то, что объект.

Ответ 4

Предположим, вы разрабатываете простую функцию, которая получает объект типа Bird и вызывает его метод walk(). Есть два подхода, о которых вы можете подумать:

  1. Это моя функция, и я должен быть уверен, что она принимает только Bird, иначе их код не скомпилируется. Если кто -то хочет использовать свою функцию, он должен знать, что я только принимая Bird s
  2. Моя функция получает любые objects и я просто вызываю метод walk(). Таким образом, если object может walk() это правильно, если он не может, моя функция завершится с ошибкой. Так что здесь не важно, что объект является Bird или чем-то еще, важно, чтобы он мог walk() (это утка)

Следует учесть, что в некоторых случаях полезность утки может быть полезной, например, Python часто использует утку.


Полезное чтение

Ответ 5

В Википедии есть довольно подробное объяснение:

http://en.wikipedia.org/wiki/Duck_typing

Утиная печать - это стиль динамического ввод, в котором текущий объект набор методов и свойств определяет действительную семантику, а чем его наследование от конкретного класса или реализации конкретного интерфейс.

Важная нота, вероятно, связана с тем, что при утиной печати разработчик больше интересуется частями предмета, которые потребляются, а не тем, что является основным базовым типом.

Ответ 6

Я вижу много ответов, которые повторяют старую идиому:

Если это похоже на утку и крякает как утка, то это утка

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

Я не нахожу такой большой помощи.

Это лучшая попытка найти простой английский ответ о наборе утки, который я нашел:

Duck Typing означает, что объект определяется тем, что он может делать, а не тем, чем он является.

Это означает, что мы меньше заботимся о классе/типе объекта и больше заботимся о том, какие методы могут быть вызваны для него и какие операции могут быть выполнены с ним. Мы не заботимся о его типе, мы заботимся о том, что он может сделать.

Ответ 7

Утка:

Если он говорит и ходит как утка, то это утка

Это обычно называется похищением (абдуктивное рассуждение или также называемое редукцией, более четкое определение, которое я думаю):

  • от C (вывод, что мы видим) и R (правило, что мы знаем), мы принимаем/решаем/принимаем P (Помещение, свойство), другими словами, данный факт

    ... сама основа медицинского диагноза

    с утками: C= прогулки, беседы, R= как утка, P= это утка

Назад к программированию:

  • объект o имеет метод/свойство mp1 и интерфейс/тип T требует/определяет mp1

  • объект o имеет метод/свойство mp2 и интерфейс/тип T требует/определяет mp2

  • ...

Итак, больше, чем просто принимать mp1... на любом объекте так долго, если он удовлетворяет некоторому определению mp1..., компилятор/время выполнения также должно быть в порядке с утверждением o имеет тип T

И хорошо, это так с примерами выше? Является ли утиная печать практически не печатаемой? Или мы будем называть это неявной типизацией?

Ответ 8

Я знаю, что не даю обобщенного ответа. В Ruby мы не объявляем типы переменных или методов - все это просто какой-то объект. Таким образом, правило - "Типы классов классов"

В Ruby класс никогда не работает (нормально, почти никогда). Вместо этого тип объекта больше определяется тем, что может сделать этот объект. В Ruby мы называем эту утиную печать. Если объект ходит как утка и говорит как утка, тогда переводчик с удовольствием относится к нему так, как если бы это была утка.

Например, вы можете писать подпрограмму для добавления информации о песнях в строку. Если вы исходите из фона С# или Java, может возникнуть соблазн написать следующее:

def append_song(result, song)
    # test we're given the right parameters 
    unless result.kind_of?(String)
        fail TypeError.new("String expected") end
    unless song.kind_of?(Song)
        fail TypeError.new("Song expected")
end

result << song.title << " (" << song.artist << ")" end
result = ""

append_song(result, song) # => "I Got Rhythm (Gene Kelly)"

Объявите печатание утиных Rubys, и youd напишите что-нибудь намного проще:

def append_song(result, song)
    result << song.title << " (" << song.artist << ")"
end

result = ""
append_song(result, song) # => "I Got Rhythm (Gene Kelly)"

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

Ответ 9

В самом деле может помочь взгляд на язык; это часто помогает мне (я не являюсь носителем английского языка).

В duck typing:

1) слово typing не означает ввод текста на клавиатуре (как и постоянное изображение в моем сознании), это означает определение того, что это за вещь?

2) слово duck выражает, как это делается; это своего рода "свободное" определение, как в: "если он ходит как утка... тогда это утка". Он "свободен", потому что это может быть утка или нет, но действительно ли это утка не имеет значения; важно то, что я могу сделать с ним то, что я могу делать с утками, и ожидать поведения, проявляемого утками. Я могу накормить его хлебными крошками, и это может пойти ко мне или обвинить меня или отступить... но это не поглотит меня, как гризли.

Ответ 10

Утиная печать не означает намек!

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

Вы можете представить себе систему, в которой хранится информация. Чтобы писать/читать информацию, вам нужно какое-то хранилище и информация.

Типы хранения могут быть: файл, база данных, сеанс и т.д.

Интерфейс позволит вам узнать доступные параметры (методы) независимо от типа хранилища, а это означает, что в этот момент ничего не реализовано! Другими словами, интерфейс ничего не знает о том, как хранить информацию.

Каждая система хранения должна знать о существовании интерфейса, реализуя его очень точно так же.

interface StorageInterface
{
   public function write(string $key, array $value): bool;
   public function read(string $key): array;
}


class File implements StorageInterface
{
    public function read(string $key): array {
        //reading from a file
    }

    public function write(string $key, array $value): bool {
         //writing in a file implementation
    }
}


class Session implements StorageInterface
{
    public function read(string $key): array {
        //reading from a session
    }

    public function write(string $key, array $value): bool {
         //writing in a session implementation
    }
}


class Storage implements StorageInterface
{
    private $_storage = null;

    function __construct(StorageInterface $storage) {
        $this->_storage = $storage;
    }

    public function read(string $key): array {
        return $this->_storage->read($key);
    }

    public function write(string $key, array $value): bool {
        return ($this->_storage->write($key, $value)) ? true : false;
    }
}

Итак, каждый раз, когда вам нужно писать/читать информацию:

$file = new Storage(new File());
$file->write('filename', ['information'] );
echo $file->read('filename');

$session = new Storage(new Session());
$session->write('filename', ['information'] );
echo $session->read('filename');

В этом примере вы в конечном итоге используете Duck Typing в конструкторе хранилища:

function __construct(StorageInterface $storage) ...

Надеюсь, что это помогло;)

Ответ 11

Обход дерева с помощью техники утки

def traverse(t):
    try:
        t.label()
    except AttributeError:
        print(t, end=" ")
    else:
        # Now we know that t.node is defined
        print('(', t.label(), end=" ")
        for child in t:
            traverse(child)
        print(')', end=" ")

Ответ 12

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

Ответ 13

Утиная печать буквально означает, вместо того, чтобы проверять класс или тип, специально указывать объекту работать так, как вы намереваетесь. Например, хотите, чтобы строковый объект указывал его (str()) или объект списка (list()) и т.д., Поэтому фраза: Если он выглядит как утка, крякает как утка и плавает как утка, то это утка, потому что вы не нужно проверять, чтобы подтвердить, когда вы уже знаете, что это за объект и что он делает. Надеюсь, это немного помогло.

Ответ 14

Моя предыдущая типизация Duck буквально означает, вместо того, чтобы проверять класс или тип, специально указывать объекту работать так, как вы намереваетесь. Например, хотите, чтобы строковый объект указывал его (str()) или объект списка (list()) и т.д., Поэтому фраза: Если он выглядит как утка, крякает как утка и плавает как утка, то это утка, потому что вы не нужно проверять, чтобы подтвердить, когда вы уже знаете, что это за объект и что он делает. Надеюсь, это немного помогло.

Ответ 15

Я пытаюсь понять знаменитое предложение по-своему: "Доза Python не волнует, является ли объект настоящей уткой или нет. Все, что его волнует, является ли объект, первый "кряк", второй "как утка". "

Есть хороший сайт. http://www.voidspace.org.uk/python/articles/duck_typing.shtml#id14

Автор указал, что утка позволяет вам создавать свои собственные классы, которые имеют их собственная внутренняя структура данных - но доступ к ней осуществляется с использованием обычного синтаксиса Python.