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"?
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"?
Respuestas:
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.
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 Quack
en un objeto.
Sin utilizar la escritura de pato, una función que f
realiza 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 donald
sea una instancia de un IQuack
subtipo.
Otro enfoque es la tipificación estructural , pero una vez más, el método Quack()
especifica formalmente cualquier cosa que no pueda probarlo quack
con 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 Quackable
clase de tipos garantiza la existencia de nuestro método.
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 f
obtiene un x
soporte 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 x
que pueda Quack
, por lo que solo intenta en tiempo de compilación y si todo funciona, está bien.
def f(x)
en lugar de def f(IQuack x)
.
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 .
Considere que está diseñando una función simple, que obtiene un objeto de tipo Bird
y llama a su walk()
método. Hay dos enfoques en los que puede pensar:
Bird
o su código no se compilará. Si alguien quiere usar mi función, debe tener en cuenta que solo acepto Bird
sobjects
y solo llamo al walk()
método del objeto . Entonces, si la object
lata walk()
es correcta, si no puede, mi función fallará. Entonces, aquí no es importante que el objeto sea un Bird
o 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 .
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.
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 .
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?
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 typing
no 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 duck
expresa 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.
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.
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;)
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.
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.