¿Qué es escribir pato?

429

Encontré el término tipeo de pato mientras leía temas aleatorios en software en línea y no lo entendí completamente.

¿Qué es "escribir pato"?

sushil bharwani
fuente
1
@Mitch probé y obtuve algo ya que es alguna forma de herencia. Pero no pudo seguir mucho. Lo siento si hice la pregunta equivocada.
sushil bharwani
3
@sushil bharwani: no, no estoy enojado. Pero la gente espera que el primer puerto de escala (es decir, lo primero que hagas) sea intentar buscar antes de publicar aquí.
Mitch Wheat
104
Teniendo en cuenta los argumentos anteriores, no parece que stackoverflow sea realmente necesario, ya que estoy seguro de que casi todas las preguntas que uno podría pensar se responden en algún lugar de Internet, y si no, la respuesta probablemente podría obtenerse más fácilmente y sin críticas enviando un correo electrónico a un amigo bien informado Creo que muchos de ustedes han perdido el punto de stackoverflow.
rhody
41
Estoy seguro de que he leído en alguna parte que SO estaba destinado a ser "un repositorio de preguntas canónicas", y estoy bastante seguro de que no puede ser más canónico que este.
heltonbiker

Respuestas:

302

Es un término utilizado en lenguajes dinámicos que no tienen una tipificación fuerte .

La idea es que no necesita un tipo para invocar un método existente en un objeto; si un método está definido en él, puede invocarlo.

El nombre proviene de la frase "Si parece un pato y grazna como un pato, es un pato".

Wikipedia tiene mucha más información.

Oded
fuente
25
Tenga cuidado al usar Strong Typing. No está tan bien definido. Tampoco Duck Typing. Google Go u Ocaml son lenguajes de tipo estático con una construcción de subtipo estructural. ¿Son estos lenguajes mecanografiados?
DOY RESPUESTAS DE MIERDA
77
una mejor frase para escribir pato es: "Si se dice que es un pato ... bueno, eso es lo suficientemente bueno para mí". ver pyvideo.org/video/1669/keynote-3 28:30 o youtube.com/watch?v=NfngrdLv9ZQ#t=1716
tovmeod
77
La escritura de pato no se usa necesariamente solo en lenguajes dinámicos. Objective-C no es un lenguaje dinámico y utiliza la escritura de pato.
eyuelt
12
Python y Ruby son lenguajes de tipo fuerte y ambos tienen Duck Typing. Typing String no implica no tener Duck Typing.
alanjds
8
Estoy rechazando esto. Duck ducking no tiene nada que ver con la fuerza del tipo, solo la capacidad de poder usar cualquier objeto que tenga un método, ya sea que implemente una interfaz o no.
e-satis
209

La tipificación de pato significa que una operación no especifica formalmente los requisitos que deben cumplir sus operandos, sino que simplemente lo prueba con lo que se le da.

A diferencia de lo que otros han dicho, esto no necesariamente se relaciona con lenguajes dinámicos o problemas de herencia.

Tarea de ejemplo: llamar a algún método Quacken un objeto.

Sin utilizar la escritura de pato, una función que frealiza esta tarea tiene que especificar de antemano que su argumento debe admitir algún método Quack. Una forma común es el uso de interfaces.

interface IQuack { 
    void Quack();
}

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

La llamada f(42)falla, pero f(donald)funciona siempre que donaldsea ​​una instancia de un IQuacksubtipo.

Otro enfoque es la tipificación estructural , pero una vez más, el método Quack()especifica formalmente cualquier cosa que no pueda probarlo quackcon anticipación causará una falla del compilador.

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

Incluso podríamos escribir

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

en Haskell, donde la Quackableclase de tipos garantiza la existencia de nuestro método.


Entonces, ¿cómo el pato escribiendo cambia esto?

Bueno, como dije, un sistema de tipeo de patos no especifica los requisitos, pero solo intenta si algo funciona .

Por lo tanto, un sistema de tipo dinámico como Python siempre usa la escritura de pato:

def f(x):
    x.Quack()

Si fobtiene un xsoporte a Quack(), todo está bien, de lo contrario, se bloqueará en tiempo de ejecución.

Pero la escritura de pato no implica en absoluto una escritura dinámica; de hecho, existe un enfoque de escritura de pato muy popular pero completamente estático que tampoco da ningún requisito:

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

La función no dice de ninguna manera que quiere algo xque pueda Quack, por lo que solo intenta en tiempo de compilación y si todo funciona, está bien.

Darío
fuente
55
no quiso decir: vacío f (IQuak x) {x.Quak (); } (en lugar de K.Quack) porque el parámetro de la función f es IQuack x no Iquack k, muy pequeño error, pero sentí que era necesario corregirlo :)
dominicbri7
Según Wikipedia, su último ejemplo es "tipificación estructural", no "tipificación de pato".
Brilliand
Bueno, parece que hay una pregunta separada para esa discusión: stackoverflow.com/questions/1948069/…
Brilliand
1
Entonces, si entiendo lo que dijiste, la diferencia entre un lenguaje que admite la escritura de pato y uno que no lo hace es solo que con la escritura de pato, ¿no tienes que especificar el tipo de objetos que acepta una función? def f(x)en lugar de def f(IQuack x).
PProteus
124

Explicación simple (sin código)

La discusión de la semántica de la pregunta es bastante matizada (y muy académica), pero esta es la idea general:

Pato escribiendo

("Si camina como un pato y grazna como un pato, entonces es un pato".) - ¡SÍ! ¡¿¿Pero qué significa eso??! Esto se ilustra mejor con un ejemplo:

Ejemplos de la funcionalidad de Duck Typing:

Imagina que tengo una varita mágica. Tiene poderes especiales. Si agito la varita y digo "¡Conduce!" a un auto, bueno, entonces conduce!

¿Funciona en otras cosas? No estoy seguro: así que lo pruebo en un camión. Wow, ¡también conduce! Luego lo pruebo en aviones, trenes y 1 Woods (son un tipo de palo de golf que la gente usa para "conducir" una pelota de golf). ¡Todos conducen!

¿Pero funcionaría en digamos, una taza de té? Error: KAAAA-BOOOOOOM! eso no funcionó tan bien. ====> ¡Las tazas de té no pueden conducir! duh?

Este es básicamente el concepto de escribir pato. Es un sistema de prueba antes de comprar . Si funciona, todo está bien. Pero si falla, como una granada aún en tu mano, te estallará en la cara.

En otras palabras, estamos interesados ​​en lo que el objeto puede hacer , más que en lo que es el objeto .

Ejemplo: idiomas escritos estáticamente

Si nos preocupara cuál era el objeto en realidad , entonces nuestro truco de magia funcionará solo en tipos preestablecidos y autorizados, en este caso automóviles, pero fallará en otros objetos que pueden conducir : camiones, ciclomotores, tuk-tuks, etc. No funcionará en camiones porque nuestra varita mágica espera que solo funcione en automóviles .

En otras palabras, en este escenario, la varita mágica se ve muy de cerca lo que el objeto es (se trata de un coche?) En lugar de lo que el objeto puede hacer (por ejemplo, si los coches, camiones etc., pueden conducir).

La única forma en que puede conducir un camión es si de alguna manera puede obtener la varita mágica para esperar tanto los camiones como los automóviles (quizás "implementando una interfaz común"). Si no sabes lo que eso significa, simplemente ignóralo por el momento.

Resumen: clave para llevar

Lo importante en la escritura de pato es lo que el objeto realmente puede hacer, en lugar de lo que es el objeto .

BKSpurgeon
fuente
Me parece interesante la premisa de que te importa más el comportamiento, esa es su definición. Sin duda, BDD tiene tanto éxito en idiomas como el rubí.
Pablo Olmos de Aguilera C.
27

Considere que está diseñando una función simple, que obtiene un objeto de tipo Birdy llama a su walk()método. Hay dos enfoques en los que puede pensar:

  1. Esta es mi función y debo asegurarme de que solo acepta Birdo su código no se compilará. Si alguien quiere usar mi función, debe tener en cuenta que solo acepto Birds
  2. Mi función obtiene any objectsy solo llamo al walk()método del objeto . Entonces, si la objectlata walk()es correcta, si no puede, mi función fallará. Entonces, aquí no es importante que el objeto sea un Birdo cualquier otra cosa, es importante que pueda walk() (Esto es escribir pato )

Debe tenerse en cuenta que la escritura de pato puede ser útil en algunos casos, por ejemplo, Python usa mucho la escritura de pato .


Lectura útil

Alireza Fattahi
fuente
1
Buena explicación, ¿cuáles son las ventajas?
sushil bharwani
2
Esta respuesta es simple, clara y probablemente la mejor para principiantes. Lea esta respuesta junto con la respuesta anterior (o si se mueve, la respuesta que habla de autos y tazas de té)
DORRITO
18

Wikipedia tiene una explicación bastante detallada:

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

la escritura de pato es un estilo de escritura dinámica en el que el conjunto actual de métodos y propiedades de un objeto determina la semántica válida, en lugar de su herencia de una clase particular o implementación de una interfaz específica.

Es probable que la nota importante sea que, al escribir el pato, un desarrollador se preocupa más por las partes del objeto que se consumen que por el tipo subyacente real.

Chris Baxter
fuente
13

Veo muchas respuestas que repiten el viejo idioma:

Si parece un pato y grazna como un pato, es un pato

y luego sumérgete en una explicación de lo que puedes hacer con la escritura de patos, o en un ejemplo que parece ofuscar aún más el concepto.

No encuentro mucha ayuda.

Este es el mejor intento de respuesta simple en inglés sobre tipeo de pato que he encontrado:

Duck Typing significa que un objeto se define por lo que puede hacer, no por lo que es.

Esto significa que estamos menos preocupados por la clase / tipo de un objeto y más preocupados por qué métodos se pueden invocar y qué operaciones se pueden realizar en él. No nos importa su tipo, nos importa lo que puede hacer .

Gerard Simpson
fuente
3

Pato escribiendo:

Si habla y camina como un pato, entonces es un pato

Esto generalmente se llama abducción ( razonamiento abductivo o también llamado retroducción , una definición más clara, creo):

  • de C (conclusión, lo que vemos ) y R (regla, lo que sabemos ), aceptamos / decidimos / asumimos P (Premisa, propiedad ) en otras palabras, un hecho dado

    ... la base misma del diagnóstico médico

    con patos: C = camina, habla , R = como un pato , P = es un pato

Volver a la programación:

  • el objeto o tiene método / propiedad mp1 y la interfaz / tipo T requiere / define mp1

  • El objeto o tiene un método / propiedad mp2 y la interfaz / tipo T requiere / define mp2

  • ...

Entonces, más que simplemente aceptar mp1 ... en cualquier objeto, siempre que cumpla con alguna definición de mp1 ..., el compilador / tiempo de ejecución también debería estar bien con la afirmación o es de tipo T

Y bueno, ¿es el caso con los ejemplos anteriores? ¿La escritura de pato es esencialmente no escribir en absoluto? ¿O deberíamos llamarlo tipeo implícito?

Djee
fuente
3

Mirar el lenguaje en sí mismo puede ayudar; a menudo me ayuda (no soy un hablante nativo de inglés).

En duck typing:

1) la palabra typingno significa escribir en un teclado (como era la imagen persistente en mi mente), significa determinar " ¿qué tipo de cosa es esa cosa? "

2) la palabra duckexpresa cómo se hace esa determinación; es una especie de determinación 'floja', como en: " si camina como un pato ... entonces es un pato ". Está 'suelto' porque la cosa puede ser un pato o no, pero no importa si realmente es un pato; lo que importa es que puedo hacer lo que puedo hacer con los patos y esperar comportamientos exhibidos por los patos. Puedo alimentarlo con migas de pan y la cosa puede ir hacia mí o cargar hacia mí o retroceder ... pero no me devorará como lo haría un oso pardo.

Arta
fuente
2

Sé que no estoy dando una respuesta generalizada. En Ruby, no declaramos los tipos de variables o métodos, todo es solo un tipo de objeto. Entonces la regla es "las clases no son tipos"

En Ruby, la clase nunca es (OK, casi nunca) el tipo. En cambio, el tipo de un objeto se define más por lo que ese objeto puede hacer. En Ruby, llamamos a este pato escribiendo. Si un objeto camina como un pato y habla como un pato, entonces el intérprete se complace en tratarlo como si fuera un pato.

Por ejemplo, puede estar escribiendo una rutina para agregar información de la canción a una cadena. Si proviene de un fondo C # o Java, puede sentirse tentado a escribir esto:

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

Abrace la escritura de pato de Ruby, y escribiría algo mucho más simple:

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

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

No necesita verificar el tipo de argumentos. Si admiten << (en el caso del resultado) o título y artista (en el caso de la canción), todo funcionará. Si no lo hacen, su método arrojará una excepción de todos modos (tal como lo habría hecho si hubiera marcado los tipos). Pero sin el cheque, su método de repente es mucho más flexible. Puede pasarle una matriz, una cadena, un archivo o cualquier otro objeto que se anexe usando <<, y simplemente funcionaría.

parar
fuente
2

Duck Typing no es una sugerencia de tipo!

Básicamente, para utilizar la "tipificación de pato", no apuntará a un tipo específico, sino a un rango más amplio de subtipos (sin hablar de herencia, cuando me refiero a subtipos me refiero a "cosas" que se ajustan a los mismos perfiles) mediante una interfaz común .

Puedes imaginar un sistema que almacene información. Para escribir / leer información necesita algún tipo de almacenamiento e información.

Los tipos de almacenamiento pueden ser: archivo, base de datos, sesión, etc.

La interfaz le permitirá conocer las opciones disponibles (métodos) independientemente del tipo de almacenamiento, lo que significa que en este momento no se implementa nada. En otras palabras, la interfaz no sabe nada sobre cómo almacenar información.

Cada sistema de almacenamiento debe conocer la existencia de la interfaz mediante la implementación de sus mismos 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;
    }
}

Ahora, cada vez que necesite escribir / leer información:

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

En este ejemplo, terminas usando Duck Typing en el constructor Storage:

function __construct(StorageInterface $storage) ...

Espero que haya ayudado;)

obinoob
fuente
2

Recorrido de árboles con técnica de tipeo de patos

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
fuente
0

Creo que es confuso mezclar la escritura dinámica, la escritura estática y la escritura de pato. La escritura de pato es un concepto independiente e incluso un lenguaje de escritura estático como Go podría tener un sistema de verificación de tipo que implementa la escritura de pato. Si un sistema de tipos verificará los métodos de un objeto (declarado) pero no el tipo, podría llamarse un lenguaje de escritura de pato.

icee
fuente
-1

Intento entender la famosa frase a mi manera: "A Python no le importa que un objeto sea un pato real o no. Lo único que le importa es si el objeto, primero 'graznido', segundo 'como un pato'".

Hay un buen sitio web. http://www.voidspace.org.uk/python/articles/duck_typing.shtml#id14

El autor señaló que la escritura de pato le permite crear sus propias clases que tienen su propia estructura interna de datos, pero a las que se accede utilizando la sintaxis normal de Python.

Robin
fuente