Qu'est-ce que la saisie de canard?


429

Je suis tombé sur le terme dactylographie en lisant des sujets aléatoires sur des logiciels en ligne et je ne l'ai pas complètement compris.

Qu'est-ce que le «typage du canard»?


1
@Mitch j'ai essayé et obtenu quelque chose comme sa forme d'héritage. Mais ne pouvait pas suivre grand-chose. Désolé si j'ai posé la mauvaise question.
sushil bharwani

3
@sushil bharwani: non, pas en colère. Mais les gens s'attendent à ce que le premier port d'escale (c'est-à-dire la première chose que vous fassiez) soit d'essayer de chercher avant de poster ici.
Mitch Wheat

104
Compte tenu des arguments ci-dessus, il ne semble pas que stackoverflow soit réellement nécessaire car je suis sûr que presque toutes les questions auxquelles on pourrait penser trouvent une réponse quelque part sur Internet, et sinon la réponse pourrait probablement être obtenue plus facilement et sans critique en envoyant un e-mail à un ami bien informé. Je pense que beaucoup d'entre vous ont raté le point de stackoverflow.
rhody

41
Je suis sûr d'avoir lu quelque part que SO devait être "un référentiel de questions canoniques", et je suis presque sûr que vous ne pouvez pas devenir plus canonique que celui-ci.
heltonbiker

Réponses:


302

C'est un terme utilisé dans les langages dynamiques qui n'ont pas de typage fort .

L'idée est que vous n'avez pas besoin d'un type pour invoquer une méthode existante sur un objet - si une méthode est définie dessus, vous pouvez l'invoquer.

Le nom vient de la phrase "Si ça ressemble à un canard et caquille comme un canard, c'est un canard".

Wikipedia a beaucoup plus d'informations.


25
Méfiez-vous de l'utilisation de Strong Typing. Ce n'est pas si bien défini. Duck Typing n'est pas non plus. Google Go ou Ocaml sont des langages typés statiquement avec une construction structurelle de sous-typage. Ces langues sont-elles typées canard?
JE DONNE DES RÉPONSES CRAP

7
une meilleure expression pour taper du canard est: "Si est dit que c'est un canard .. eh bien c'est assez bon pour moi." voir pyvideo.org/video/1669/keynote-3 28:30 ou youtube.com/watch?v=NfngrdLv9ZQ#t=1716
tovmeod

7
Le typage canard n'est pas nécessairement utilisé uniquement dans les langages dynamiques. Objective-C n'est pas un langage dynamique et utilise le typage canard.
eyuelt

12
Python et Ruby sont tous deux des langages de type fort et tous deux ont Duck Typing. Le typage de chaînes n'implique pas de ne pas avoir de typage de canard.
alanjds

8
Je sous-vote cela. Le canard esquivant n'a rien à voir avec la force du type, juste la possibilité de pouvoir utiliser n'importe quel objet ayant une méthode, qu'il implémente une interface ou non.
e-satis

209

Le typage canard signifie qu'une opération ne spécifie pas formellement les exigences que ses opérandes doivent satisfaire, mais l' essaye simplement avec ce qui est donné.

Contrairement à ce que d'autres ont dit, cela ne concerne pas nécessairement les langues dynamiques ou les problèmes d'héritage.

Exemple de tâche: appeler une méthode Quacksur un objet.

Sans utiliser de type de canard, une fonction feffectuant cette tâche doit spécifier à l'avance que son argument doit prendre en charge une méthode Quack. Une manière courante est l'utilisation d'interfaces

interface IQuack { 
    void Quack();
}

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

L'appel f(42)échoue, mais f(donald)fonctionne tant qu'il donalds'agit d'une instance d'un sous- IQuacktype.

Une autre approche est le typage structurel - mais encore une fois, la méthode Quack()est formellement spécifiée tout ce qui ne peut pas le prouver quackà l'avance entraînera une défaillance du compilateur.

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

On pourrait même écrire

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

à Haskell, où la Quackabletypeclass assure l'existence de notre méthode.


Alors, comment la frappe de canard change-t-elle cela?

Eh bien, comme je l'ai dit, un système de typage canard ne spécifie pas les exigences mais essaie simplement si quelque chose fonctionne .

Ainsi, un système de type dynamique comme celui de Python utilise toujours le typage canard:

def f(x):
    x.Quack()

Si fobtient un xsupport Quack(), tout va bien, sinon, il se bloquera lors de l'exécution.

Mais le typage de canard n'implique pas du tout de typage dynamique - en fait, il existe une approche de typage de canard très populaire mais complètement statique qui ne donne pas non plus d'exigences:

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

La fonction ne dit en aucune manière qu'il en veut xque peut Quack, donc au lieu qu'il essaie juste au moment de la compilation et si tout fonctionne, il va bien.


5
ne voulais-tu pas dire: void f (IQuak x) {x.Quak (); } (au lieu de K.Quack) parce que le paramètre de la fonction f est IQuack x pas Iquack k, très petite erreur mais j'avais l'impression qu'il fallait la corriger :)
dominicbri7

Selon Wikipedia, votre dernier exemple est le "typage structurel", pas le "typage canard".
Brilliand

Eh bien, il semble qu'il y ait une question distincte pour cette discussion: stackoverflow.com/questions/1948069/…
Brilliand

1
Donc, si je comprends ce que vous avez dit, la différence entre un langage qui prend en charge le typage canard et un autre qui ne l'est pas uniquement avec le typage canard, vous n'avez pas à spécifier le type d'objets qu'une fonction accepte? def f(x)au lieu de def f(IQuack x).
PProteus

124

Explication simple (sans code)

La discussion de la sémantique de la question est assez nuancée (et très académique), mais voici l'idée générale:

Dactylographie de canard

("Si ça marche comme un canard et caquille comme un canard alors c'est un canard.") - OUI! Mais qu'est ce que ça veut dire??! Ceci est mieux illustré par l'exemple:

Exemples de fonctionnalités de Duck Typing:

Imaginez que j'ai une baguette magique. Il a des pouvoirs spéciaux. Si j'agite la baguette et dis "Drive!" à une voiture, eh bien, elle roule!

Cela fonctionne-t-il sur d'autres choses? Pas sûr: alors je l'essaye sur un camion. Wow - ça roule aussi! Je l'essaie ensuite sur des avions, des trains et 1 Woods (c'est un type de club de golf que les gens utilisent pour «conduire» une balle de golf). Ils conduisent tous!

Mais cela fonctionnerait-il, disons, une tasse de thé? Erreur: KAAAA-BOOOOOOM! cela n'a pas fonctionné si bien. ====> Les tasses à thé ne peuvent pas conduire !! duh !?

Il s'agit essentiellement du concept de frappe de canard. C'est un système à essayer avant d'acheter . Si ça marche, tout va bien. Mais si ça échoue, comme une grenade toujours dans votre main, ça va exploser dans votre visage.

En d'autres termes, nous nous intéressons à ce que l'objet peut faire , plutôt qu'à ce qu'est l'objet .

Exemple: langues typées statiquement

Si nous étions préoccupés par ce qu'était réellement l'objet , alors notre tour de magie ne fonctionnera que sur les types autorisés prédéfinis - dans ce cas, les voitures, mais échouera sur d'autres objets qui peuvent conduire : camions, cyclomoteurs, tuk-tuks, etc. Il ne fonctionnera pas sur les camions car notre baguette magique s'attend à ce qu'il ne fonctionne que sur les voitures .

En d' autres termes, dans ce scénario, la baguette magique regarde de très près ce que l'objet est (est - ce une voiture?) Plutôt que ce que l'objet peut faire (par exemple , si les voitures, les camions etc. peuvent conduire).

La seule façon de faire conduire un camion est de pouvoir en quelque sorte faire en sorte que la baguette magique s’attende à la fois aux camions et aux voitures (peut-être en «mettant en œuvre une interface commune»). Si vous ne savez pas ce que cela signifie, ignorez-le pour le moment.

Résumé: clés à emporter

Ce qui est important dans la dactylographie de canard est ce que l'objet peut réellement faire, plutôt que ce que l'objet est .


Je trouve intéressant la prémisse selon laquelle vous vous souciez plus du comportement, c'est sa définition. Nul doute que BDD connaît un tel succès dans des langues comme le rubis.
Pablo Olmos de Aguilera C.

27

Considérez que vous concevez une fonction simple, qui obtient un objet de type Birdet appelle sa walk()méthode. Il existe deux approches auxquelles vous pouvez penser:

  1. C'est ma fonction et je dois être sûr qu'elle n'accepte que les Bird, sinon leur code ne se compilera pas. Si quelqu'un veut utiliser ma fonction, il doit être conscient que je n'accepte que Birdles
  2. Ma fonction en obtient objectset j'appelle simplement la walk()méthode de l'objet . Donc, si la objectboîte walk()est correcte, si elle ne le peut pas, ma fonction échouera. Donc ici, il n'est pas important que l'objet soit un Birdou autre chose, il est important qu'il le puisse walk() (c'est du typage de canard )

Il faut tenir compte du fait que le typage canard peut être utile dans certains cas, par exemple Python utilise beaucoup le typage canard .


Lecture utile


1
Belle explication, quels sont les avantages?
sushil bharwani

2
Cette réponse est simple, claire et probablement la meilleure pour les débutants. Lisez cette réponse avec la réponse au-dessus (ou si elle bouge, la réponse qui parle de voitures et de tasses à thé)
DORRITO

18

Wikipedia a une explication assez détaillée:

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

le typage canard est un style de typage dynamique dans lequel l'ensemble actuel de méthodes et de propriétés d'un objet détermine la sémantique valide, plutôt que son héritage d'une classe particulière ou l'implémentation d'une interface spécifique.

La note importante est probable qu'avec la frappe de canard, un développeur se préoccupe davantage des parties de l'objet qui sont consommées plutôt que du type réel sous-jacent.


13

Je vois beaucoup de réponses qui répètent l'ancien idiome:

Si ça ressemble à un canard et caquet comme un canard, c'est un canard

puis plongez dans une explication de ce que vous pouvez faire avec la frappe de canard, ou un exemple qui semble obscurcir davantage le concept.

Je ne trouve pas beaucoup d'aide.

C'est la meilleure tentative de réponse en anglais simple sur la saisie de canard que j'ai trouvée:

Duck Typing signifie qu'un objet est défini par ce qu'il peut faire, pas par ce qu'il est.

Cela signifie que nous sommes moins préoccupés par la classe / le type d'un objet et plus préoccupés par les méthodes qui peuvent être appelées dessus et les opérations qui peuvent y être effectuées. Nous ne nous soucions pas de son type, nous nous soucions de ce qu'il peut faire .


3

Dactylographie de canard:

S'il parle et marche comme un canard, alors c'est un canard

Ceci est généralement appelé abduction ( raisonnement abductif ou aussi appelé rétroduction , une définition plus claire, je pense):

  • de C (conclusion, ce que nous voyons ) et R (règle, ce que nous savons ), nous acceptons / décidons / supposons P (prémisse, propriété ) en d'autres termes un fait donné

    ... la base même du diagnostic médical

    avec des canards: C = marche, parle , R = comme un canard , P = c'est un canard

Retour à la programmation:

  • l'objet o a la méthode / propriété mp1 et l'interface / le type T requiert / définit mp1

  • l'objet o a la méthode / propriété mp2 et l'interface / le type T nécessite / définit mp2

  • ...

Donc, plus que d'accepter simplement mp1 ... sur n'importe quel objet tant qu'il répond à une définition de mp1 ..., le compilateur / runtime devrait également être d'accord avec l'assertion o est de type T

Et bien, est-ce le cas avec les exemples ci-dessus? Est-ce que Duck typing est essentiellement pas de frappe du tout? Ou devrions-nous appeler cela une frappe implicite?


3

Regarder la langue elle-même peut aider; ça m'aide souvent (je ne suis pas natif anglophone).

Dans duck typing:

1) le mot typingne signifie pas taper sur un clavier (comme l'était l'image persistante dans mon esprit), cela signifie déterminer " quel type de chose est cette chose? "

2) le mot duckexprime comment se fait cette détermination; c'est une sorte de détermination 'lâche', comme dans: " s'il marche comme un canard ... alors c'est un canard ". C'est «lâche» parce que la chose peut être un canard ou non, mais que ce soit réellement un canard n'a pas d'importance; ce qui compte, c'est que je puisse en faire ce que je peux faire avec les canards et m'attendre à des comportements manifestés par des canards. Je peux lui donner de la chapelure et la chose peut aller vers moi ou me charger ou reculer ... mais elle ne me dévorera pas comme le ferait un grizzly.


2

Je sais que je ne donne pas de réponse généralisée. Dans Ruby, nous ne déclarons pas les types de variables ou de méthodes - tout n'est qu'une sorte d'objet. La règle est donc "les classes ne sont pas des types"

Dans Ruby, la classe n'est jamais (OK, presque jamais) le type. Au lieu de cela, le type d'un objet est davantage défini par ce que cet objet peut faire. En Ruby, nous appelons ce type de canard. Si un objet marche comme un canard et parle comme un canard, alors l'interprète est heureux de le traiter comme s'il s'agissait d'un canard.

Par exemple, vous pouvez écrire une routine pour ajouter des informations de morceau à une chaîne. Si vous venez d'un arrière-plan C # ou Java, vous pourriez être tenté d'écrire ceci:

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)"

Embrassez la saisie de canard de Ruby, et vous écririez quelque chose de beaucoup plus simple:

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

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

Vous n'avez pas besoin de vérifier le type des arguments. S'ils supportent << (dans le cas du résultat) ou le titre et l'artiste (dans le cas de la chanson), tout fonctionnera simplement. S'ils ne le font pas, votre méthode lèvera quand même une exception (tout comme elle l'aurait fait si vous aviez vérifié les types). Mais sans le contrôle, votre méthode est soudainement beaucoup plus flexible. Vous pouvez lui passer un tableau, une chaîne, un fichier ou tout autre objet ajouté à l'aide de <<, et cela fonctionnerait simplement.


2

Duck Typing n'est pas un indice de type!

Fondamentalement, pour utiliser le "typage du canard", vous ne ciblerez pas un type spécifique mais plutôt une gamme plus large de sous-types (je ne parle pas d'héritage, quand je veux dire des sous-types, je veux dire des "choses" qui correspondent aux mêmes profils) en utilisant une interface commune .

Vous pouvez imaginer un système qui stocke des informations. Pour écrire / lire des informations, vous avez besoin d'une sorte de stockage et d'informations.

Les types de stockage peuvent être: fichier, base de données, session, etc.

L'interface vous fera connaître les options (méthodes) disponibles quel que soit le type de stockage, ce qui signifie qu'à ce stade, rien n'est implémenté! En d'autres termes, l'interface ne sait rien sur la façon de stocker des informations.

Chaque système de stockage doit connaître l'existence de l'interface en implémentant ses mêmes méthodes.

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;
    }
}

Alors maintenant, chaque fois que vous devez écrire / lire des informations:

$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');

Dans cet exemple, vous finissez par utiliser Duck Typing dans le constructeur de stockage:

function __construct(StorageInterface $storage) ...

J'espère que cela a aidé;)


2

Traversée d'arbre avec technique de frappe de canard

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=" ")

0

Je pense qu'il est confus de mélanger la frappe dynamique, la frappe statique et la frappe de canard. Le typage canard est un concept indépendant et même un langage typé statique comme Go, pourrait avoir un système de vérification de type qui implémente le typage canard. Si un système de types vérifie les méthodes d'un objet (déclaré) mais pas le type, il pourrait être appelé un langage de frappe de canard.


-1

J'essaie de comprendre la fameuse phrase à ma manière: "La dose de python ne fait pas attention à un objet est un vrai canard ou pas.

Il y a un bon site Web. http://www.voidspace.org.uk/python/articles/duck_typing.shtml#id14

L'auteur a souligné que le typage de canard vous permet de créer vos propres classes qui ont leur propre structure de données interne - mais qui sont accessibles en utilisant la syntaxe Python normale.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.