O que é digitação de pato?

429

Me deparei com o termo digitação de pato enquanto lia tópicos aleatórios no software on-line e não o entendia completamente.

O que é "digitação de pato"?

sushil bharwani
fonte
1
@ Mitch tentei e consegui algo como sua forma de herança. Mas não consegui acompanhar muito. Desculpe se eu fiz a pergunta errada.
sushil bharwani
3
@sushil bharwani: não, não com raiva. Mas as pessoas esperam que, como o primeiro porto de escala (ou seja, a primeira coisa que você faça), tente pesquisar antes de postar aqui.
Mitch Wheat
104
Dado os argumentos acima, não parece que o stackoverflow seja realmente necessário, pois tenho certeza de que quase todas as perguntas em que alguém poderia pensar são respondidas em algum lugar da Internet. Caso contrário, a resposta provavelmente poderia ser obtida com mais facilidade e sem críticas, enviando um e-mail a amigo experiente. Eu acho que muitos de vocês perderam o ponto do stackoverflow.
rhody
41
Tenho certeza de que li em algum lugar que o SO pretendia ser "um repositório de perguntas canônicas" e tenho certeza de que você não pode ser mais canônico do que este.
heltonbiker

Respostas:

302

É um termo usado em linguagens dinâmicas que não possuem digitação forte .

A idéia é que você não precisa de um tipo para chamar um método existente em um objeto - se um método estiver definido nele, você poderá invocá-lo.

O nome vem da frase "Se parece um pato e grasna como um pato, é um pato".

A Wikipedia tem muito mais informações.

Oded
fonte
25
Desconfie de usar Digitação Forte. Não é tão bem definido. Nem é Duck Typing. Google Go ou Ocaml são linguagens de tipo estaticamente com uma construção de subtipagem estrutural. Esses idiomas são do tipo pato?
DUO RESPOSTAS AO EXCREMENTO
7
uma frase melhor para digitação de pato é: "Se diz que é um pato ... bem, isso é bom o suficiente para mim". consulte pyvideo.org/video/1669/keynote-3 28:30 ou youtube.com/watch?v=NfngrdLv9ZQ#t=1716
tovmeod
7
A digitação com patos não é necessariamente usada apenas em idiomas dinâmicos. Objective-C não é uma linguagem dinâmica e usa digitação de pato.
eyuelt
12
Tanto o Python quanto o Ruby são linguagens de tipo forte e ambos têm Duck Typing. A digitação de string não implica em não ter Duck Typing.
alanjds
8
Estou votando contra isso. Duck ducking não tem nada a ver com a força do tipo, apenas a capacidade de poder usar qualquer objeto que possua um método, quer implemente uma interface ou não.
e-satis
209

A digitação com pato significa que uma operação não especifica formalmente os requisitos que seus operandos devem atender, mas apenas tenta com o que é fornecido.

Ao contrário do que outros disseram, isso não está necessariamente relacionado a linguagens dinâmicas ou problemas de herança.

Tarefa de exemplo: chame algum método Quackem um objeto.

Sem usar a digitação de pato, uma função que fexecuta esta tarefa deve especificar antecipadamente que seu argumento deve suportar algum método Quack. Uma maneira comum é o uso de interfaces

interface IQuack { 
    void Quack();
}

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

A chamada f(42)falha, mas f(donald)funciona desde que donaldseja uma instância de um IQuacksubtipo.

Outra abordagem é a tipagem estrutural - mas, novamente, o método Quack()é formalmente especificado. Qualquer coisa que não possa provar quackcom antecedência causará uma falha no compilador.

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

Poderíamos até escrever

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

em Haskell, onde a Quackableclasse garante a existência do nosso método.


Então, como a digitação com patos muda isso?

Bem, como eu disse, um sistema de digitação de pato não especifica requisitos, mas apenas tenta se algo funcionar .

Assim, um sistema de tipo dinâmico como o do Python sempre usa digitação de pato:

def f(x):
    x.Quack()

Se fobtiver um a de xsuporte Quack(), tudo estará bem; caso contrário, ele falhará em tempo de execução.

Mas a digitação com patos não implica em digitação dinâmica - na verdade, existe uma abordagem de digitação com patos muito popular, mas completamente estática, que também não fornece requisitos:

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

A função não diz de forma alguma que ela quer algo xque possa Quack, então, em vez disso, apenas tenta em tempo de compilação e, se tudo funcionar, tudo bem.

Dario
fonte
5
você não quis dizer: void f (IQuak x) {x.Quak (); } (Em vez de K.Quack) porque o parâmetro função de f é IQuack X não Iquack k, muito pequeno erro, mas eu senti que precisava ser corrigida :)
dominicbri7
Segundo a Wikipedia, seu último exemplo é "digitação estrutural", não "digitação de pato".
Brilliand
Bem, parece que há uma pergunta separada para essa discussão: stackoverflow.com/questions/1948069/…
Brilliand
1
Então, se eu entendo o que você disse, a diferença entre um idioma que suporta digitação por patos e um que não é exatamente o mesmo com a digitação por patos, você não precisa especificar o tipo de objeto que uma função aceita? def f(x)em vez de def f(IQuack x).
precisa saber é o seguinte
124

Explicação simples (sem código)

A discussão da semântica da pergunta é bastante sutil (e muito acadêmica), mas aqui está a ideia geral:

Digitação de pato

(“Se ele anda como um pato e grasna como um pato, então é um pato.”) - SIM! Mas o que isso significa??! Isso é melhor ilustrado pelo exemplo:

Exemplos de funcionalidade Duck Typing:

Imagine que eu tenho uma varinha mágica. Tem poderes especiais. Se eu acenar com a varinha e disser "Dirija!" para um carro, então ele dirige!

Isso funciona em outras coisas? Não tenho certeza: então eu tento em um caminhão. Uau - ele dirige também! Em seguida, tento em aviões, trens e 1 Woods (eles são um tipo de taco de golfe que as pessoas usam para 'dirigir' uma bola de golfe). Todos eles dirigem!

Mas funcionaria, digamos, uma xícara de chá? Erro: KAAAA-BOOOOOOM! isso não funcionou tão bem. ====> Xícaras de chá não podem dirigir !! duh !?

Este é basicamente o conceito de digitação de pato. É um sistema de experimentar antes de comprar . Se funcionar, está tudo bem. Mas se falhar, como uma granada ainda na sua mão, vai explodir na sua cara.

Em outras palavras, estamos interessados ​​no que o objeto pode fazer , e não no que o objeto é .

Exemplo: idiomas de tipo estaticamente

Se estivéssemos preocupados com o que o objeto realmente era , nosso truque de mágica funcionará apenas em tipos autorizados predefinidos - nesse caso, carros, mas falhará em outros objetos que podem dirigir : caminhões, ciclomotores, tuk-tuks etc. Não funciona em caminhões, porque nossa varinha mágica espera que funcione apenas em carros .

Em outras palavras, nesse cenário, a varinha mágica olha muito de perto o que o objeto é (é um carro?) E não o que o objeto pode fazer (por exemplo, se carros, caminhões etc. podem dirigir).

A única maneira de conseguir um caminhão para dirigir é se, de alguma forma, conseguir que a varinha mágica espere caminhões e carros (talvez "implementando uma interface comum"). Se você não sabe o que isso significa, basta ignorá-lo por enquanto.

Resumo: retirada principal

O que é importante na digitação do pato é o que o objeto pode realmente fazer, e não o que o objeto é .

BKSpurgeon
fonte
Acho interessante que a premissa sobre você se preocupa mais com o comportamento, é a definição. Sem dúvida, o BDD é tão bem-sucedido em idiomas como ruby.
Pablo Olmos de Aguilera C.
27

Considere que você está criando uma função simples, que obtém um objeto do tipo Birde chama seu walk()método. Existem duas abordagens, nas quais você pode pensar:

  1. Essa é a minha função e devo ter certeza de que ela aceita apenas o Birdcódigo ou o código não será compilado. Se alguém quiser usar a minha função, ele deve estar ciente de que eu só aceitar Birds
  2. Minha função obtém any objectse eu apenas chamo o walk()método do objeto . Portanto, se a objectlata walk()estiver correta, se não puder, minha função falhará. Portanto, aqui não é importante que o objeto seja um Birdou qualquer outra coisa, é importante que ele possa walk() (esta é a digitação do pato )

Deve-se considerar que a digitação do pato pode ser útil em alguns casos, por exemplo, o Python usa muito a digitação do pato .


Leitura útil

Alireza Fattahi
fonte
1
Boa explicação, quais são as vantagens?
sushil bharwani
2
Esta resposta é simples, clara e provavelmente a melhor para iniciantes. Leia esta resposta, juntamente com a resposta acima dele (ou se ele se move, a resposta que fala sobre carros e xícaras de chá)
DORRITO
18

A Wikipedia tem uma explicação bastante detalhada:

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

A tipagem duck é um estilo de digitação dinâmica, no qual o conjunto atual de métodos e propriedades de um objeto determina a semântica válida, em vez de sua herança de uma classe específica ou implementação de uma interface específica.

A observação importante é provável que, com a digitação do duck, um desenvolvedor se preocupe mais com as partes do objeto que são consumidas do que com o tipo subjacente real.

Chris Baxter
fonte
13

Vejo muitas respostas que repetem o idioma antigo:

Se parece um pato e grasna como um pato, é um pato

e depois explique o que você pode fazer com a digitação de patos, ou um exemplo que parece ofuscar ainda mais o conceito.

Não encontro muita ajuda.

Esta é a melhor tentativa de uma resposta simples em inglês sobre digitação de patos que eu encontrei:

Duck Typing significa que um objeto é definido pelo que ele pode fazer, não pelo que é.

Isso significa que estamos menos preocupados com a classe / tipo de um objeto e mais preocupados com quais métodos podem ser chamados e quais operações podem ser executadas nele. Não nos preocupamos com o seu tipo, nos preocupamos com o que ele pode fazer .

Gerard Simpson
fonte
3

Digitação de pato:

Se ele fala e anda como um pato, então é um pato

Isso geralmente é chamado de abdução ( raciocínio abdutivo ou também chamado de retrodução , uma definição mais clara, eu acho):

  • de C (conclusão, o que vemos ) e R (regra, o que sabemos ), aceitamos / decidimos / assumimos P (Premissa, propriedade ) em outras palavras, um dado fato

    ... a própria base do diagnóstico médico

    com patos: C = passeios, conversas , R = como um pato , P = é um pato

Voltar à programação:

  • objeto o possui método / propriedade mp1 e interface / tipo T requer / define mp1

  • objeto o possui método / propriedade mp2 e interface / tipo T requer / define mp2

  • ...

Portanto, mais do que simplesmente aceitar mp1 ... em qualquer objeto, desde que ele atenda a alguma definição de mp1 ..., o compilador / tempo de execução também deve estar bem com a afirmação o é do tipo T

E bem, é o caso dos exemplos acima? A digitação com Duck é essencialmente sem digitação? Ou deveríamos chamá-lo de digitação implícita?

Djee
fonte
3

Olhar para o próprio idioma pode ajudar; isso geralmente me ajuda (não sou um falante nativo de inglês).

Em duck typing:

1) a palavra typingnão significa digitar em um teclado (como era a imagem persistente em minha mente), significa determinar " que tipo de coisa é essa coisa? "

2) a palavra duckexpressa como é feita essa determinação; é uma espécie de determinação 'solta', como em: " se andar como um pato ... então é um pato ". É "frouxo" porque a coisa pode ser um pato ou não, mas se realmente é um pato não importa; o que importa é que eu possa fazer com ele o que posso fazer com patos e esperar comportamentos exibidos por patos. Eu posso alimentá-lo com migalhas de pão e a coisa pode ir em minha direção, atacar ou recuar ... mas não vai me devorar como um urso pardo.

Arta
fonte
2

Eu sei que não estou dando uma resposta generalizada. Em Ruby, não declaramos os tipos de variáveis ​​ou métodos - tudo é apenas algum tipo de objeto. Portanto, a regra é "Classes não são tipos"

Em Ruby, a classe nunca é (OK, quase nunca) o tipo. Em vez disso, o tipo de um objeto é definido mais pelo que esse objeto pode fazer. Em Ruby, chamamos isso de digitação de pato. Se um objeto anda como um pato e fala como um pato, o intérprete fica feliz em tratá-lo como se fosse um pato.

Por exemplo, você pode estar escrevendo uma rotina para adicionar informações da música a uma string. Se você tem experiência em C # ou Java, pode ser tentado a escrever o seguinte:

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

Aceite a digitação de pato de Ruby e você escreveria algo muito mais simples:

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

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

Você não precisa verificar o tipo dos argumentos. Se eles suportarem << (no caso de resultado) ou título e artista (no caso de música), tudo funcionará. Se não o fizerem, seu método lançará uma exceção de qualquer maneira (como faria se você tivesse verificado os tipos). Mas sem a verificação, seu método fica subitamente muito mais flexível. Você pode passar uma matriz, uma string, um arquivo ou qualquer outro objeto que acrescente usando <<, e funcionaria.

desviar-se
fonte
2

A digitação de pato não é uma dica de tipo!

Basicamente, para usar a "tipagem de pato", você não terá como alvo um tipo específico, mas uma variedade maior de subtipos (sem falar em herança, quando eu quero dizer subtipos, quero dizer "coisas" que se encaixam nos mesmos perfis) usando uma interface comum .

Você pode imaginar um sistema que armazena informações. Para escrever / ler informações, você precisa de algum tipo de armazenamento e informações.

Os tipos de armazenamento podem ser: arquivo, banco de dados, sessão etc.

A interface informará as opções disponíveis (métodos), independentemente do tipo de armazenamento, o que significa que, neste momento, nada é implementado! Em outras palavras, a Interface não sabe nada sobre como armazenar informações.

Todo sistema de armazenamento deve conhecer a existência da interface implementando os mesmos métodos.

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

Então agora, toda vez que você precisar escrever / ler informações:

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

Neste exemplo, você acaba usando o construtor Duck Typing in Storage:

function __construct(StorageInterface $storage) ...

Espero que tenha ajudado;)

obinoob
fonte
2

Traversal de árvore com técnica de digitação de pato

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=" ")
Rajat
fonte
0

Eu acho que é confuso misturar digitação dinâmica, estática e pato. A digitação com patos é um conceito independente e até mesmo a linguagem estática, como Go, pode ter um sistema de verificação de tipos que implementa a digitação com patos. Se um sistema de tipos verificar os métodos de um objeto (declarado), mas não o tipo, isso poderá ser chamado de linguagem de digitação duck.

icee
fonte
-1

Tento entender a famosa frase do meu jeito: "Python não liga para um objeto ser um pato real ou não. Tudo o que importa é se o objeto, primeiro 'charlatão', segundo 'como um pato'".

Existe um bom site. http://www.voidspace.org.uk/python/articles/duck_typing.shtml#id14

O autor apontou que a digitação com patos permite criar suas próprias classes que possuem sua própria estrutura de dados interna - mas são acessadas usando a sintaxe normal do Python.

Robin
fonte