Я натрапив на термін « качка, коли я читав випадкові теми в Інтернеті та не зрозумів його повністю».
Що таке "качка набравши"?
Я натрапив на термін « качка, коли я читав випадкові теми в Інтернеті та не зрозумів його повністю».
Що таке "качка набравши"?
Відповіді:
Це термін, що використовується в динамічних мовах , які не мають сильного введення тексту .
Ідея полягає в тому, що вам не потрібен тип, щоб викликати існуючий метод на об'єкті - якщо метод визначений на ньому, ви можете викликати його.
Назва походить від фрази "Якщо вона схожа на качку, і какає, як качка, це качка".
У Вікіпедії є набагато більше інформації.
Введення качки означає, що операція формально не визначає вимоги, яким повинні відповідати її операнди, а просто випробовує її з тим, що задано.
На відміну від сказаних іншими, це не обов'язково стосується динамічних мов чи питань успадкування.
Приклад завдання: Викликати якийсь метод Quack
на об'єкт.
Не використовуючи набору качок, функція, яка f
виконує це завдання, повинна заздалегідь вказати, що її аргумент повинен підтримувати якийсь метод Quack
. Поширений спосіб - використання інтерфейсів
interface IQuack {
void Quack();
}
void f(IQuack x) {
x.Quack();
}
Виклик f(42)
не вдається, але f(donald)
працює до тих пір, donald
поки є екземпляром IQuack
підтипу.
Інший підхід - це структурна типізація - але, знову ж таки, метод Quack()
формально визначає будь-що, що не може довести його quack
заздалегідь, спричинить збій компілятора.
def f(x : { def Quack() : Unit }) = x.Quack()
Ми навіть могли написати
f :: Quackable a => a -> IO ()
f = quack
в Haskell, де Quackable
клас класу забезпечує існування нашого методу.
Ну, як я вже сказав, система набору качок не визначає вимог, а просто намагається, якщо щось працює .
Таким чином, система динамічного типу, як Python, завжди використовує введення качок:
def f(x):
x.Quack()
Якщо f
отримує , x
що підтримує Quack()
все нормально, якщо немає, то він буде врізатися під час виконання.
Але введення качок взагалі не передбачає динамічного набору тексту - насправді існує дуже популярний, але повністю статичний підхід набору качки, який також не пред'являє жодних вимог:
template <typename T>
void f(T x) { x.Quack(); }
Функція жодним чином не говорить про те, що хоче щось, x
що може Quack
, тому натомість просто намагається під час компіляції, і якщо все працює, це добре.
def f(x)
замість def f(IQuack x)
.
Обговорення семантики питання є досить нюансованим (і дуже академічним), але ось загальна ідея:
Введення качки
("Якщо вона ходить, як качка, і какає, як качка, то це качка.") - ТАК! але що це означає ??! Це найкраще проілюструє приклад:
Приклади функціональності друку качок:
Уявіть, у мене є чарівна паличка. Він має особливі повноваження. Якщо я помахую паличкою і скажу "Зажену!до машини, ну тоді їде!
Чи працює це на інші речі? Не впевнений: тому я спробую це на вантажівці. Нічого собі - теж їздить! Потім я спробую це в літаках, поїздах та на 1 Вудсі (це тип гольф-клубу, який люди використовують для 'водіння' м'яча для гольфу). Вони всі їздять!
Але чи попрацювало б це, скажімо, чашка? Помилка: KAAAA-BOOOOOOM! це не вийшло так добре. ====> Чайники не можуть їздити !! так !?
Це в основному концепція набору качок. Це спроба перед покупкою . Якщо це працює, все добре. Але якщо вона вийде з ладу, як граната, яка все ще знаходиться в руці, вона підірветься вам в обличчя.
Іншими словами, нас цікавить, що може робити об’єкт , а не те, що є об’єктом .
Приклад: статично набрані мови
Якщо ми переймалися тим, що насправді був об’єктом , то наш магічний трюк буде працювати лише на заздалегідь встановлених, дозволених типах - у цьому випадку на автомобілях, але не вдасться до інших об'єктів, які можуть їздити : вантажівки, мопеди, тук-тюки тощо. Він не буде працювати на вантажівках, тому що наша чарівна паличка очікує, що вона працюватиме лише на автомобілях .
Іншими словами, в цьому випадку, магія дуже близько паличка дивиться на те , що об'єкт є (це автомобіль?) , А не те , що об'єкт може зробити (наприклад , є чи автомобілі, вантажівки і т.д. можуть їздити).
Єдиний спосіб, як можна змусити вантажівку керувати, це якщо ви зможете якось отримати чарівну паличку, щоб очікувати як вантажівки, так і автомобілі (можливо, "впровадивши загальний інтерфейс"). Якщо ви не знаєте, що це означає, тоді просто ігноруйте це.
Резюме: Ключовий винос
Що важливо в качиної типізації є те , що об'єкт може реально зробити, а не те , що об'єкт знаходиться .
Розглянемо, що ви проектуєте просту функцію, яка отримує об'єкт типу Bird
і викликає його walk()
метод. Можна придумати два підходи:
Bird
, або їх код не буде компілюватися. Якщо хтось хоче використовувати мою функцію, він повинен усвідомлювати, що я приймаю лише Bird
sobjects
і я просто називаю walk()
метод об'єкта . Отже, якщо object
вміє walk()
правильно, якщо не може, то моя функція не спрацює. Тож тут не важливо, об'єкт є Bird
чи що-небудь інше, важливо, що він може walk()
(Це введення качки )Потрібно враховувати, що типізація качок може бути корисною в деяких випадках, наприклад, Python багато використовує качки, набираючи качок .
У Вікіпедії є досить детальне пояснення:
http://en.wikipedia.org/wiki/Duck_typing
типи качок - це стиль динамічного введення тексту, в якому поточний набір методів і властивостей об'єкта визначає дійсну семантику, а не її успадкування з певного класу чи реалізацію певного інтерфейсу.
Важлива примітка, ймовірно, що при наборі качок розробник стосується більше тих частин об'єкта, які споживаються, а не того, що є фактичним базовим типом.
Я бачу багато відповідей, які повторюють стару ідіому:
Якщо він схожий на качку і трясе як качка - це качка
а потім зануритися в пояснення того, що ти можеш зробити з набором качок, або приклад, який, здається, ще більше заплутує концепцію.
Я не знаходжу такої великої допомоги.
Це найкраща спроба англійської відповіді про введення качки, яку я знайшов:
Введення качки означає, що об’єкт визначається тим, що він може робити, а не тим, що він є.
Це означає, що ми менше переймаємось класом / типом об’єкта і більше переймаємось тим, які методи можна викликати на ньому та які операції на ньому можна виконувати. Нас не хвилює його тип, ми дбаємо про те, що він може робити .
Введення качки:
Якщо вона розмовляє і ходить, як качка, то це качка
Це , як правило , називають відведенням ( абдуктівним міркуванням або також називають retroduction , більш чітким визначенням я думаю):
з C (висновок, що ми бачимо ) і R (правило, те , що ми знаємо ), ми приймаємо / вирішуємо / припускаємо P (приміщення, властивість ), іншими словами, даний факт
... сама основа медичної діагностики
з качками: C = гуляє, розмовляє , R = як качка , P = це качка
Повернутися до програмування:
Об'єкт o має метод / властивість mp1, а інтерфейс / тип T вимагає / визначає mp1
Об'єкт o має метод / властивість mp2 та інтерфейс / тип T вимагає / визначає mp2
...
Отже, більш ніж просто прийняття mp1 ... на будь-якому об'єкті, поки він відповідає деякому визначенню mp1 ..., компілятор / час виконання також повинен відповідати твердженню o типу T
І добре, чи справа в наведених вище прикладах? Невже типізація качки насправді взагалі не вводить текст? Або ми повинні називати це неявним введенням тексту?
Погляд на саму мову може допомогти; це часто допомагає мені (я не є носієм англійської мови).
В duck typing
:
1) слово typing
не означає введення на клавіатурі (як це було стійке зображення в моїй свідомості), воно означає визначення " який тип речі - це річ? "
2) слово duck
виражає, як робиться таке визначення; це щось на кшталт "розкутого" визначення, як у: " якщо воно ходить як качка ... то це качка ". Це "вільно", тому що річ може бути качкою, а може і ні, але чи це насправді качка, не має значення; Що важливо, це те, що я можу з ним робити те, що я можу робити з качками, і очікувати поведінки, яку демонструють качки. Я можу його нагодувати хлібними крихтами, і річ може піти назустріч мені або зарядити мене або відмовитися ... але це не пожирає мене так, як хотілося б грізлі.
Я знаю, що не даю узагальненої відповіді. У Ruby ми не оголошуємо типи змінних чи методів - все це лише якийсь об’єкт. Отже, правило - "Класи не є типами"
У Ruby клас ніколи не буває (добре, майже ніколи). Натомість тип об'єкта визначається більше тим, що може зробити цей об’єкт. У Рубі ми називаємо цю качку типізацією. Якщо предмет ходить як качка і розмовляє, як качка, то перекладач із задоволенням ставиться до нього так, ніби до качки.
Наприклад, ви можете написати процедуру, щоб додати інформацію про пісні до рядка. Якщо ви походили з C # або 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)"
Обійміть качку Рубі, і ви напишете щось набагато простіше:
def append_song(result, song)
result << song.title << " (" << song.artist << ")"
end
result = ""
append_song(result, song) # => "I Got Rhythm (Gene Kelly)"
Не потрібно перевіряти тип аргументів. Якщо вони підтримують << (у випадку результату) або назву та виконавця (у випадку пісні), все просто працюватиме. Якщо цього не зробити, ваш метод все одно викине виняток (так само, як це було б, якби ви перевірили типи). Але без перевірки ваш метод раптом набагато гнучкіший. Ви можете передати йому масив, рядок, файл або будь-який інший об'єкт, який додається за допомогою <<, і він би просто працював.
Введення качок не є натяком типу!
В основному, щоб використовувати "типи качок", ви не орієнтуєтесь на конкретний тип, а на ширший діапазон підтипів (не кажучи про спадщину, коли я маю на увазі підтипи, я маю на увазі "речі", що підходять до одних і тих же профілів), використовуючи загальний інтерфейс .
Можна уявити систему, яка зберігає інформацію. Для того, щоб писати / читати інформацію, вам потрібні певні сховища та інформація.
Типи сховища можуть бути: файл, база даних, сеанс тощо.
Інтерфейс повідомить вам про доступні параметри (методи) незалежно від типу зберігання, це означає, що на даний момент нічого не реалізовано! Іншими словами, Інтерфейс нічого не знає, як зберігати інформацію.
Кожна система зберігання даних повинна знати існування інтерфейсу, застосовуючи дуже однакові методи.
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 в конструкторі Storage:
function __construct(StorageInterface $storage) ...
Сподіваюся, це допомогло;)
Я думаю, що це заплутано в поєднанні динамічного набору тексту, статичного набору тексту та качки. Введення качок - це незалежна концепція і навіть статична мова, що набирається типу, як Go, може мати систему перевірки типів, яка реалізує введення качок. Якщо система типів перевірятиме методи (оголошеного) об'єкта, а не тип, це може бути названо мовою набору качки.
Я намагаюся зрозуміти відоме речення своїм способом: "Доза Пітона не піклується про об’єкт - це справжня качка чи ні. Все, що це хвилює, чи є об'єкт, перший" крякання ", другий" як качка ".
Є хороший веб-сайт. http://www.voidspace.org.uk/python/articles/duck_typing.shtml#id14
Автор вказав, що введення качок дозволяє створювати власні класи, які мають власну внутрішню структуру даних, але доступ до них використовується за допомогою звичайного синтаксису Python.