A menos que me equivoque, crear una función en Python funciona así:
def my_func(param1, param2):
# stuff
Sin embargo, en realidad no proporciona los tipos de esos parámetros. Además, si recuerdo, Python es un lenguaje fuertemente tipado, como tal, parece que Python no debería permitirle pasar un parámetro de un tipo diferente al que esperaba el creador de la función. Sin embargo, ¿cómo sabe Python que el usuario de la función está pasando los tipos adecuados? ¿El programa simplemente morirá si es del tipo incorrecto, suponiendo que la función realmente use el parámetro? ¿Tienes que especificar el tipo?
python
function
parameters
Leif Andersen
fuente
fuente
Respuestas:
Python está fuertemente tipado porque cada objeto tiene un tipo, cada objeto conoce su tipo, es imposible usar accidental o deliberadamente un objeto de un tipo "como si" fuera un objeto de un tipo diferente , y todas las operaciones elementales en el objeto son delegado a su tipo.
Esto no tiene nada que ver con los nombres . Un nombre en Python no "tiene un tipo": si y cuando se define un nombre, el nombre se refiere a un objeto , y el objeto tiene un tipo (pero de hecho eso no fuerza un tipo en el nombre : un nombre es un nombre).
Un nombre en Python puede referirse perfectamente a diferentes objetos en diferentes momentos (como en la mayoría de los lenguajes de programación, aunque no en todos), y no hay ninguna restricción en el nombre que, si alguna vez se ha referido a un objeto de tipo X, está por siempre limitado a referirse solo a otros objetos de tipo X. Las restricciones en los nombres no son parte del concepto de "escritura fuerte", aunque algunos entusiastas de la escritura estática (donde los nombres no quedan limitados, y en una estática, también conocido como de compilación el tiempo, la moda también) hacen un mal uso del término de esta manera.
fuente
try
/except
) ocurrirá cuando y si se intenta una operación que el objeto no admite. En Python 3.5 ahora puede opcionalmente "especificar tipos" de argumentos, pero no se produce ningún error, per se, si se viola la especificación; la notación de escritura solo está destinada a ayudar a separar las herramientas que realizan análisis, etc., no altera el comportamiento de Python.Las otras respuestas han hecho un buen trabajo al explicar la escritura de los patos y la respuesta simple de tzot :
Sin embargo , una cosa interesante ha cambiado desde 2010 (cuando se hizo la pregunta por primera vez), a saber, la implementación de PEP 3107 (implementado en Python 3). Ahora puede especificar el tipo de parámetro y el tipo de retorno de una función como esta:
Podemos ver aquí que
pick
toma 2 parámetros, una listal
y un número enteroindex
. También debería devolver un número entero.Entonces, aquí está implícito que
l
es una lista de enteros que podemos ver sin mucho esfuerzo, pero para funciones más complejas puede ser un poco confuso lo que debe contener la lista. También queremos que el valor predeterminadoindex
sea 0. Para resolver esto, puede optar por escribirpick
así:Tenga en cuenta que ahora ponemos una cadena como el tipo de
l
, que está sintácticamente permitido, pero no es bueno para el análisis mediante programación (que volveremos más adelante).Es importante tener en cuenta que Python no generará un aumento
TypeError
si pasa un flotadorindex
, la razón de esto es uno de los puntos principales en la filosofía de diseño de Python: "Aquí todos aceptamos adultos" , lo que significa que se espera que usted tenga en cuenta lo que puede pasar a una función y lo que no puede. Si realmente desea escribir código que arroje TypeErrors, puede usar laisinstance
función para verificar que el argumento pasado sea del tipo apropiado o una subclase de este tipo:En la siguiente sección y en los comentarios se habla más sobre por qué rara vez se debe hacer esto y qué se debe hacer en su lugar.
PEP 3107 no solo mejora la legibilidad del código, sino que también tiene varios casos de uso adecuados que puede leer aquí .
La anotación de tipo recibió mucha más atención en Python 3.5 con la introducción de PEP 484, que presenta un módulo estándar para sugerencias de tipo.
Estas sugerencias de tipo provienen del verificador de tipo mypy ( GitHub ), que ahora cumple con PEP 484 .
Con el módulo de mecanografía viene con una colección bastante completa de sugerencias de tipos, que incluyen:
List
,Tuple
,Set
,Map
- paralist
,tuple
,set
ymap
respectivamente.Iterable
- útil para generadores.Any
- Cuando podría ser cualquier cosa.Union
- cuando podría ser cualquier cosa dentro de un conjunto específico de tipos, a diferencia deAny
.Optional
- Cuando podría ser Ninguno. Taquigrafía paraUnion[T, None]
.TypeVar
- Utilizado con genéricos.Callable
- se usa principalmente para funciones, pero podría usarse para otras llamadas.Estas son las sugerencias de tipo más comunes. Se puede encontrar una lista completa en la documentación del módulo de escritura .
Aquí está el viejo ejemplo usando los métodos de anotación introducidos en el módulo de escritura:
Una característica poderosa es la
Callable
que le permite escribir métodos de anotación que toman una función como argumento. Por ejemplo:El ejemplo anterior podría volverse más preciso con el uso de en
TypeVar
lugar deAny
, pero esto se ha dejado como un ejercicio para el lector, ya que creo que ya llené mi respuesta con demasiada información sobre las nuevas características maravillosas habilitadas por las sugerencias de tipo.Anteriormente, cuando se documentaba un código de Python con, por ejemplo, Sphinx, algunas de las funciones anteriores se podían obtener escribiendo cadenas de documentos con el siguiente formato:
Como puede ver, esto requiere varias líneas adicionales (el número exacto depende de cuán explícito quiera ser y de cómo formatee su cadena de documentación). Pero ahora debería estar claro para usted cómo PEP 3107 proporciona una alternativa que es superior en muchos (¿todos?). Esto es especialmente cierto en combinación con PEP 484 que, como hemos visto, proporciona un módulo estándar que define una sintaxis para este tipo de sugerencias / anotaciones que se pueden usar de tal manera que sea inequívoca y precisa pero flexible, lo que hace que Potente combinación.
En mi opinión personal, esta es una de las mejores características de Python. No puedo esperar a que la gente empiece a aprovechar su poder. Perdón por la respuesta larga, pero esto es lo que sucede cuando me emociono.
Aquí se puede encontrar un ejemplo de código de Python que usa muchas sugerencias de tipo .
fuente
TypeError
, ¿cuál es el punto de usarpick(l: list, index: int) -> int
como definición de una línea? O me equivoqué, no lo sé.__annotations__
atributo del objeto de función).def f(a) -> Tuple[int, int]:
No especificas un tipo. El método solo fallará (en tiempo de ejecución) si intenta acceder a los atributos que no están definidos en los parámetros que se pasan.
Entonces esta simple función:
... no fallará sin importar qué dos argumentos se pasen.
Sin embargo, esta función:
... se producirá un error en tiempo de ejecución si
param1
yparam2
no tanto tener atributos exigibles nombradasquack
.fuente
Muchos idiomas tienen variables, que son de un tipo específico y tienen un valor. Python no tiene variables; tiene objetos, y usa nombres para referirse a estos objetos.
En otros idiomas, cuando dices:
entonces una variable (típicamente entera) cambia su contenido al valor 1.
En Python
significa "usar el nombre a para referirse al objeto 1 ". Puede hacer lo siguiente en una sesión interactiva de Python:
La función
type
se llama con el objeto1
; Como cada objeto conoce su tipo, es fáciltype
encontrar dicho tipo y devolverlo.Del mismo modo, cada vez que defina una función
la función recibe dos objetos, y los nombra
param1
yparam2
, independientemente de sus tipos. Si desea asegurarse de que los objetos recibidos sean de un tipo específico, codifique su función como si fueran del tipo o tipos necesarios y capture las excepciones que se generan si no lo son. Las excepciones lanzadas son típicamenteTypeError
(utilizó una operación no válida) yAttributeError
(intentó acceder a un miembro inexistente (los métodos también son miembros)).fuente
Python no está fuertemente tipado en el sentido de comprobación de tipo estático o en tiempo de compilación.
La mayor parte del código de Python se encuentra en el llamado "Duck Typing" , por ejemplo, busca un método
read
en un objeto; no le importa si el objeto es un archivo en el disco o un socket, solo desea leer N bytes de ella.fuente
Como explica Alex Martelli ,
Lea el resto de su publicación para obtener información útil.
fuente
A Python no le importa lo que pases a sus funciones. Cuando llame
my_func(a,b)
, las variables param1 y param2 mantendrán los valores de a y b. Python no sabe que está llamando a la función con los tipos adecuados, y espera que el programador se encargue de eso. Si se llamará a su función con diferentes tipos de parámetros, puede ajustar el código de acceso a ellos con bloques try / except y evaluar los parámetros de la manera que desee.fuente
Nunca especifiques el tipo; Python tiene el concepto de escribir pato ; Básicamente, el código que procesa los parámetros hará ciertas suposiciones sobre ellos, quizás llamando a ciertos métodos que se espera que implemente un parámetro. Si el parámetro es del tipo incorrecto, se generará una excepción.
En general, depende de su código asegurarse de que está pasando objetos del tipo adecuado; no hay un compilador para hacer cumplir esto con anticipación.
fuente
Hay una notable excepción al tipeo de patos que vale la pena mencionar en esta página.
Cuando la
str
función llama al__str__
método de clase, verifica sutilmente su tipo:Como si Guido nos insinuara qué excepción debería generar un programa si encuentra un tipo inesperado.
fuente
En Python todo tiene un tipo. Una función de Python hará cualquier cosa que se le pida que haga si el tipo de argumentos lo admite.
Ejemplo:
foo
agregará todo lo que se puede__add__
editar;) sin preocuparse mucho por su tipo. Eso significa que, para evitar fallas, debe proporcionar solo aquellas cosas que admiten la adición.fuente
No vi esto mencionado en otras respuestas, así que lo agregaré al bote.
Como otros han dicho, Python no impone el tipo en los parámetros de función o método. Se asume que usted sabe lo que está haciendo y que si realmente necesita saber el tipo de algo que se pasó, lo comprobará y decidirá qué hacer por usted mismo.
Una de las principales herramientas para hacer esto es la función isinstance ().
Por ejemplo, si escribo un método que espera obtener datos de texto binario sin formato, en lugar de las cadenas codificadas utf-8 normales, podría verificar el tipo de parámetros en el camino y adaptarme a lo que encuentro, o elevar un excepción a rechazar.
Python también proporciona todo tipo de herramientas para excavar en objetos. Si eres valiente, incluso puedes usar importlib para crear tus propios objetos de clases arbitrarias, sobre la marcha. Hice esto para recrear objetos a partir de datos JSON. Tal cosa sería una pesadilla en un lenguaje estático como C ++.
fuente
Para utilizar de manera efectiva el módulo de mecanografía (nuevo en Python 3.5) incluya all (
*
).Y estará listo para usar:
Sin embargo, todavía se puede utilizar como nombres de tipos
int
,list
,dict
, ...fuente
He implementado un contenedor si alguien quisiera especificar tipos de variables.
Úselo como:
EDITAR
El código anterior no funciona si alguno de los argumentos '(o el tipo de devolución) no se declara. La siguiente edición puede ayudar, por otro lado, solo funciona para kwargs y no verifica los args.
fuente