Che cos'è la tipizzazione anatra?


429

Mi sono imbattuto nel termine digitando anatra mentre leggevo argomenti casuali su software online e non l'ho capito del tutto.

Che cos'è la "tipizzazione anatra"?


1
@Mitch ho provato e ottenuto qualcosa come una qualche forma di eredità. Ma non ho potuto seguire molto. Scusa se ho fatto la domanda sbagliata.
sushil bharwani,

3
@sushil bharwani: no, non arrabbiato. Ma la gente si aspetta che come primo porto di scalo (ovvero la prima cosa che fai) sia provare a cercare prima di pubblicare qui.
Mitch Wheat,

104
Alla luce degli argomenti sopra riportati, non sembra che StackOverflow sia effettivamente necessario poiché sono sicuro che quasi ogni domanda a cui uno potrebbe pensare è una risposta da qualche parte su Internet, e in caso contrario la risposta potrebbe probabilmente essere ottenuta più facilmente e senza critiche inviando un'e-mail a amico esperto. Penso che molti di voi abbiano perso il punto di StackOverflow.
rhody

41
Sono sicuro di aver letto da qualche parte che SO doveva essere "un deposito di domande canoniche", e sono abbastanza sicuro che non puoi diventare più canonico di questo.
Heltonbiker,

Risposte:


302

È un termine usato in linguaggi dinamici che non hanno una digitazione forte .

L'idea è che non è necessario un tipo per invocare un metodo esistente su un oggetto: se un metodo è definito su di esso, è possibile invocarlo.

Il nome deriva dalla frase "Se sembra un'anatra e ciondola come un'anatra, è un'anatra".

Wikipedia ha molte più informazioni.


25
Diffidare di usare la tipizzazione forte. Non è così ben definito. Nemmeno Duck Typing. Google Go o Ocaml sono linguaggi tipicamente statici con una sottostruttura strutturale. Sono queste lingue dattiloscritte?
RISPONDO A CRAP il

7
una frase migliore per scrivere l'anatra è: "Se si dice che è un'anatra ... beh, questo è abbastanza buono per me." vedi pyvideo.org/video/1669/keynote-3 28:30 o youtube.com/watch?v=NfngrdLv9ZQ#t=1716
tovmeod

7
La digitazione anatra non è necessariamente utilizzata solo nei linguaggi dinamici. Objective-C non è un linguaggio dinamico e utilizza la tipizzazione duck.
eyuelt,

12
Sia Python che Ruby sono linguaggi tipicamente forti ed entrambi hanno Duck Typing. La digitazione di stringhe non implica la mancata digitazione anatra.
alanjds,

8
Sto sottovalutando questo. L'anatra all'anatra non ha nulla a che fare con la forza del tipo, solo la capacità di essere in grado di utilizzare qualsiasi oggetto che abbia un metodo, sia che implementi un'interfaccia o meno.
Soddisfa il

209

La tipizzazione anatra significa che un'operazione non specifica formalmente i requisiti che i suoi operandi devono soddisfare, ma lo prova semplicemente con ciò che viene dato.

A differenza di ciò che altri hanno detto, ciò non si riferisce necessariamente a linguaggi dinamici o problemi di eredità.

Attività di esempio: chiamare un metodo Quacksu un oggetto.

Senza utilizzare la digitazione anatra, una funzione che fesegue questa attività deve specificare in anticipo che il suo argomento deve supportare un metodo Quack. Un modo comune è l'uso di interfacce

interface IQuack { 
    void Quack();
}

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

La chiamata ha f(42)esito negativo, ma f(donald)funziona fintanto che donaldè un'istanza di un IQuacksottotipo.

Un altro approccio è la tipizzazione strutturale - ma ancora una volta, il metodo Quack()è formalmente specificato qualsiasi cosa che non possa dimostrarlo quackin anticipo causerà un errore del compilatore.

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

Potremmo persino scrivere

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

in Haskell, dove la Quackabletypeclass garantisce l'esistenza del nostro metodo.


Quindi, come si digita l'anatra cambia questo?

Bene, come ho detto, un sistema di tipizzazione anatra non specifica i requisiti, ma cerca solo se qualcosa funziona .

Pertanto, un sistema di tipo dinamico come quello di Python utilizza sempre la tipizzazione duck:

def f(x):
    x.Quack()

Se fottiene un xsupporto a Quack(), tutto va bene, altrimenti si bloccherà in fase di esecuzione.

Ma la tipizzazione anatra non implica affatto la tipizzazione dinamica - in effetti, esiste un approccio molto popolare ma completamente statico alla tipizzazione anatra che non presenta alcun requisito:

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

La funzione non dice in alcun modo che vuole qualcosa xche può Quack, quindi invece cerca solo in fase di compilazione e se tutto funziona, va bene.


5
non volevi dire: void f (IQuak x) {x.Quak (); } (invece di K.Quack) perché il parametro della funzione f è IQuack x non Iquack k, un errore molto piccolo ma ho sentito che doveva essere corretto :)
dominicbri7

Secondo Wikipedia, il tuo ultimo esempio è la "tipizzazione strutturale", non la "tipizzazione anatra".
Brilliand,

Bene, sembra che ci sia una domanda separata per quella discussione: stackoverflow.com/questions/1948069/…
Brilliand

1
Quindi, se capisco quello che hai detto, la differenza tra una lingua che supporta la tipizzazione di anatre e una che non lo è è quella con la tipizzazione di anatre, non devi specificare il tipo di oggetti che una funzione accetta? def f(x)invece di def f(IQuack x).
PProteo,

124

Spiegazione semplice (senza codice)

La discussione sulla semantica della domanda è abbastanza sfumata (e molto accademica), ma ecco l'idea generale:

Duck Typing

("Se cammina come un'anatra e ciondola come un'anatra, allora è un'anatra.") - SÌ! ma cosa significa ??! Questo è meglio illustrato dall'esempio:

Esempi di funzionalità di digitazione anatra:

Immagina di avere una bacchetta magica. Ha poteri speciali. Se agito la bacchetta e dico "Guida!"ad un'auto, bene, allora guida!

Funziona su altre cose? Non sono sicuro: quindi lo provo su un camion. Wow - guida anche tu! Poi lo provo su aerei, treni e 1 bosco (sono un tipo di mazza da golf che la gente usa per "guidare" una pallina da golf). Tutti guidano!

Ma funzionerebbe, diciamo, una tazza da tè? Errore: KAAAA-BOOOOOOM! non ha funzionato così bene. ====> Le tazze da tè non possono guidare !! duh !?

Questo è fondamentalmente il concetto di tipizzazione anatra. È un sistema da provare prima di acquistare . Se funziona, va tutto bene. Ma se fallisce, come una granata ancora in mano, ti esploderà in faccia.

In altre parole, siamo interessati a ciò che l'oggetto può fare , piuttosto che a ciò che l'oggetto è .

Esempio: lingue tipicamente statiche

Se eravamo preoccupati di cosa fosse effettivamente l'oggetto , allora il nostro trucco magico funzionerà solo su tipi preimpostati e autorizzati - in questo caso le auto, ma fallirà su altri oggetti che possono guidare : camion, ciclomotori, tuk-tuk ecc. Non funzionerà sui camion perché la nostra bacchetta magica si aspetta che funzioni solo sulle auto .

In altre parole, in questo scenario, la bacchetta magica aspetto molto da vicino a ciò che l'oggetto è (si tratta di una macchina?), Piuttosto che ciò che l'oggetto può fare (per esempio se le automobili, camion, ecc possono guidare).

L'unico modo in cui puoi guidare un camion è se riesci in qualche modo a far sì che la bacchetta magica si aspetti sia camion che automobili (forse "implementando un'interfaccia comune"). Se non sai cosa significhi, ignoralo per il momento.

Riepilogo: estrazione chiave

Ciò che è importante nella tipizzazione anatra è ciò che l'oggetto può effettivamente fare, piuttosto che ciò che l'oggetto è .


Trovo interessante la premessa che ti interessa di più del comportamento, questa è la definizione. Senza dubbio BDD ha così tanto successo in lingue come il rubino.
Pablo Olmos de Aguilera C.

27

Considera che stai progettando una funzione semplice, che ottiene un oggetto di tipo Birde chiama il suo walk()metodo. Esistono due approcci a cui puoi pensare:

  1. Questa è la mia funzione e devo essere sicuro che accetta solo il Bird, o il loro codice non verrà compilato. Se qualcuno vuole usare la mia funzione, deve essere consapevole che accetto solo Birds
  2. La mia funzione ne ottiene una objectse chiamo semplicemente il walk()metodo dell'oggetto . Quindi, se la objectlattina walk()è corretta, se non è possibile la mia funzione fallirà. Quindi qui non è importante che l'oggetto sia Birdo qualsiasi altra cosa, è importante che possa walk() (questo è il tipo di anatra )

Bisogna considerare che la tipizzazione duck può essere utile in alcuni casi, ad esempio Python usa molto la tipizzazione duck .


Lettura utile


1
Bella spiegazione, quali sono i vantaggi?
sushil bharwani,

2
Questa risposta è semplice, chiara e probabilmente la migliore per i principianti. Leggi questa risposta insieme alla risposta sopra di essa (o se si muove, la risposta che parla di auto e tazze da tè)
DORRITO

18

Wikipedia ha una spiegazione abbastanza dettagliata:

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

la tipizzazione duck è uno stile di tipizzazione dinamica in cui l'insieme corrente di metodi e proprietà di un oggetto determina la semantica valida, piuttosto che la sua eredità da una particolare classe o implementazione di una specifica interfaccia.

La nota importante è probabile che con la tipizzazione anatra uno sviluppatore si preoccupi più delle parti dell'oggetto che vengono consumate piuttosto che del tipo reale sottostante.


13

Vedo molte risposte che ripetono il vecchio linguaggio:

Se sembra un'anatra e ciondola come un'anatra, è un'anatra

e poi immergiti in una spiegazione di cosa puoi fare con la digitazione dell'anatra, o in un esempio che sembra offuscare ulteriormente il concetto.

Non trovo molto aiuto.

Questo è il miglior tentativo di una semplice risposta inglese sulla digitazione di anatre che ho trovato:

Duck Typing significa che un oggetto è definito da ciò che può fare, non da ciò che è.

Ciò significa che siamo meno preoccupati della classe / tipo di un oggetto e più preoccupati di quali metodi possono essere chiamati su di esso e quali operazioni possono essere eseguite su di esso. Non ci interessa il suo tipo, ci preoccupiamo di cosa può fare .


3

Duck typing:

Se parla e cammina come un'anatra, allora è un'anatra

Questo è tipicamente chiamato rapimento ( ragionamento abduttivo o anche retroduzione , una definizione più chiara penso):

  • da C (conclusione, ciò che vediamo ) e R (regola, ciò che sappiamo ), accettiamo / decidiamo / assumiamo P (Premessa, proprietà ) in altre parole un dato fatto

    ... le basi stesse della diagnosi medica

    con le anatre: C = cammina, parla , R = come un'anatra , P = è un'anatra

Torna alla programmazione:

  • l'oggetto o ha metodo / proprietà mp1 e interfaccia / tipo T richiede / definisce mp1

  • l'oggetto o ha metodo / proprietà mp2 e interfaccia / tipo T richiede / definisce mp2

  • ...

Quindi, oltre ad accettare semplicemente mp1 ... su qualsiasi oggetto, purché soddisfi una definizione di mp1 ..., il compilatore / runtime dovrebbe anche andare bene con l'affermazione o è di tipo T

E bene, è il caso degli esempi sopra? La tipizzazione Duck è essenzialmente nessuna tipizzazione? O dovremmo chiamarlo tipizzazione implicita?


3

Guardare la lingua stessa può aiutare; mi aiuta spesso (non sono un madrelingua inglese).

In duck typing:

1) la parola typingnon significa digitare su una tastiera (come era l'immagine persistente nella mia mente), significa determinare " che tipo di cosa è quella cosa? "

2) la parola duckesprime come è fatta quella determinazione; è una specie di determinazione "libera", come in: " se cammina come un'anatra ... allora è un'anatra ". È "sciolto" perché la cosa può essere un'anatra o no, ma non importa se in realtà è un'anatra; ciò che conta è che posso farci ciò che posso fare con le anatre e aspettarmi comportamenti mostrati dalle anatre. Posso dargli da mangiare le briciole di pane e la cosa potrebbe andare verso di me o caricarmi o arretrare ... ma non mi divorerà come farebbe un grizzly.


2

So di non dare una risposta generalizzata. In Ruby non dichiariamo i tipi di variabili o metodi: tutto è solo una specie di oggetto. Quindi la regola è "Le classi non sono tipi"

In Ruby, la classe non è mai (OK, quasi mai) il tipo. Invece, il tipo di un oggetto è definito più da ciò che quell'oggetto può fare. In Ruby, chiamiamo questa anatra digitando. Se un oggetto cammina come un'anatra e parla come un'anatra, allora l'interprete è felice di trattarlo come se fosse un'anatra.

Ad esempio, potresti scrivere una routine per aggiungere informazioni sul brano a una stringa. Se provieni da uno sfondo C # o Java, potresti essere tentato di scrivere questo:

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

Abbraccia la tipografia di Ruby e scriverai qualcosa di molto più semplice:

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

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

Non è necessario controllare il tipo di argomenti. Se supportano << (nel caso del risultato) o titolo e artista (nel caso del brano), tutto funzionerà. In caso contrario, il tuo metodo genererà comunque un'eccezione (proprio come avrebbe fatto se avessi controllato i tipi). Ma senza il controllo, il tuo metodo è improvvisamente molto più flessibile. Potresti passargli un array, una stringa, un file o qualsiasi altro oggetto che accoda usando <<, e funzionerebbe.


2

Duck Typing non è un suggerimento sul tipo!

Fondamentalmente per usare la "tipizzazione anatra" non sceglierai un tipo specifico ma piuttosto una gamma più ampia di sottotipi (non parliamo di eredità, quando intendo i sottotipi intendo "cose" che si adattano all'interno degli stessi profili) usando un'interfaccia comune .

Puoi immaginare un sistema che memorizza informazioni. Per scrivere / leggere le informazioni hai bisogno di una sorta di memoria e informazione.

I tipi di archiviazione possono essere: file, database, sessione ecc.

L'interfaccia ti farà conoscere le opzioni disponibili (metodi) indipendentemente dal tipo di archiviazione, il che significa che a questo punto nulla è implementato! In altre parole, l'interfaccia non sa nulla su come archiviare le informazioni.

Ogni sistema di archiviazione deve conoscere l'esistenza dell'interfaccia implementando i suoi stessi metodi.

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

Quindi, ogni volta che devi scrivere / leggere informazioni:

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

In questo esempio si finisce per utilizzare Duck Typing nel costruttore di archiviazione:

function __construct(StorageInterface $storage) ...

Spero che abbia aiutato;)


2

Tree Traversal con tecnica di battitura delle anatre

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

Penso che sia confuso mescolare la digitazione dinamica, la digitazione statica e la digitazione anatra. La tipizzazione anatra è un concetto indipendente e persino un linguaggio tipizzato statico come Go, potrebbe avere un sistema di controllo del tipo che implementa la tipizzazione anatra. Se un sistema di tipi controllerà i metodi di un oggetto (dichiarato) ma non il tipo, potrebbe essere chiamato un linguaggio di tipizzazione duck.


-1

Cerco di capire la famosa frase a modo mio: "La dose di Python non importa se un oggetto è una vera anatra o no. Tutto ciò che importa è se l'oggetto, prima" ciarlatano ", secondo" come un'anatra "."

C'è un buon sito web. http://www.voidspace.org.uk/python/articles/duck_typing.shtml#id14

L'autore ha sottolineato che la tipizzazione duck consente di creare le proprie classi con una propria struttura di dati interna, ma a cui si accede utilizzando la normale sintassi di Python.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.