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»?
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»?
Réponses:
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.
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 Quack
sur un objet.
Sans utiliser de type de canard, une fonction f
effectuant 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 donald
s'agit d'une instance d'un sous- IQuack
type.
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 Quackable
typeclass assure l'existence de notre méthode.
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 f
obtient un x
support 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 x
que peut Quack
, donc au lieu qu'il essaie juste au moment de la compilation et si tout fonctionne, il va bien.
def f(x)
au lieu de def f(IQuack x)
.
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 .
Considérez que vous concevez une fonction simple, qui obtient un objet de type Bird
et appelle sa walk()
méthode. Il existe deux approches auxquelles vous pouvez penser:
Bird
, sinon leur code ne se compilera pas. Si quelqu'un veut utiliser ma fonction, il doit être conscient que je n'accepte que Bird
lesobjects
et j'appelle simplement la walk()
méthode de l'objet . Donc, si la object
boî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 Bird
ou 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 .
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.
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 .
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?
Regarder la langue elle-même peut aider; ça m'aide souvent (je ne suis pas natif anglophone).
Dans duck typing
:
1) le mot typing
ne 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 duck
exprime 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.
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.
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é;)
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.
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.