parameter - typing io python
Python 3 y tipeo estático (5)
¡Gracias por leer mi código!
De hecho, no es difícil crear un ejecutor de anotación genérico en Python. Aquí está mi opinión:
''''''Very simple enforcer of type annotations.
This toy super-decorator can decorate all functions in a given module that have
annotations so that the type of input and output is enforced; an AssertionError is
raised on mismatch.
This module also has a test function func() which should fail and logging facility
log which defaults to print.
Since this is a test module, I cut corners by only checking *keyword* arguments.
''''''
import sys
log = print
def func(x:''int'' = 0) -> ''str'':
''''''An example function that fails type checking.''''''
return x
# For simplicity, I only do keyword args.
def check_type(*args):
param, value, assert_type = args
log(''Checking {0} = {1} of {2}.''.format(*args))
if not isinstance(value, assert_type):
raise AssertionError(
''Check failed - parameter {0} = {1} not {2}.''
.format(*args))
return value
def decorate_func(func):
def newf(*args, **kwargs):
for k, v in kwargs.items():
check_type(k, v, ann[k])
return check_type(''<return_value>'', func(*args, **kwargs), ann[''return''])
ann = {k: eval(v) for k, v in func.__annotations__.items()}
newf.__doc__ = func.__doc__
newf.__type_checked = True
return newf
def decorate_module(module = ''__main__''):
''''''Enforces type from annotation for all functions in module.''''''
d = sys.modules[module].__dict__
for k, f in d.items():
if getattr(f, ''__annotations__'', {}) and not getattr(f, ''__type_checked'', False):
log(''Decorated {0!r}.''.format(f.__name__))
d[k] = decorate_func(f)
if __name__ == ''__main__'':
decorate_module()
# This will raise AssertionError.
func(x = 5)
Dada esta simplicidad, es extraño a primera vista que esto no sea convencional. Sin embargo, creo que hay buenas razones por las cuales no es tan útil como podría parecer . En general, la verificación de tipos ayuda porque si agregas un entero y un diccionario, es probable que hayas cometido un error obvio (y si quisieras decir algo razonable, es mejor ser explícito que implícito ).
Pero en la vida real a menudo se mezclan cantidades del mismo tipo de computadora que ve el compilador, pero un tipo humano claramente diferente, por ejemplo, el siguiente fragmento contiene un error obvio:
height = 1.75 # Bob''s height in meters.
length = len(sys.modules) # Number of modules imported by program.
area = height * length # What''s that supposed to mean???
Cualquier humano debería ver inmediatamente un error en la línea anterior, siempre que conozca el "tipo humano" de variables de height
y length
, aunque parezca que la computadora es una multiplicación perfectamente legal de int
y float
.
Se puede decir más acerca de las posibles soluciones a este problema, pero hacer cumplir los "tipos de computadora" es aparentemente una solución a medias, por lo que, al menos en mi opinión, es peor que ninguna solución . Es la misma razón por la cual Systems Hungarian es una idea terrible, mientras que Apps Hungarian es una gran idea. Hay más en la publicación muy informativa de Joel Spolsky .
Ahora bien, si alguien fuera a implementar algún tipo de biblioteca Pythonic de terceros que automáticamente asignara datos del mundo real a su tipo humano y luego se encargara de transformar ese tipo como width * height -> area
y aplicar esa verificación con anotaciones de funciones, ¡Piensa que sería un tipo de control que la gente realmente podría usar!
Realmente no presté tanta atención al desarrollo de Python 3 como me hubiera gustado, y solo noté algunos nuevos e interesantes cambios de sintaxis. Específicamente, a partir de esta anotación de parámetro de función SO answer :
def digits(x:''nonnegative number'') -> "yields number''s digits":
# ...
¡Sin saber nada sobre esto, pensé que podría ser usado para implementar tipeo estático en Python!
Después de algunas búsquedas, pareció haber mucha discusión con respecto al tipado estático (totalmente opcional) en Python, como el mencionado en PEP 3107 , y "Agregar tipado estático opcional a Python" (y parte 2 )
... pero no estoy seguro de cuánto ha progresado esto. ¿Hay alguna implementación de tipado estático, usando el parámetro-anotación? ¿Alguna de las ideas de tipo parametrizado lo convirtió en Python 3?
Claro, el tipado estático parece un poco "antipático" y no lo uso todo el tiempo. Pero hay casos (por ejemplo, clases anidadas, como en el análisis de lenguaje específico del dominio) donde realmente puede acelerar su desarrollo.
Entonces prefiero usar beartype explicado en esta post *. Viene con un git repo, pruebas y una explicación de lo que puede y lo que no puede hacer ... y me gusta el nombre;)
* Por favor, no presten atención a la diatriba de Cecil sobre por qué Python no viene con las baterías incluidas en este caso.
Como se menciona en ese PEP, la comprobación estática de tipos es una de las aplicaciones posibles para las que se pueden utilizar las anotaciones, pero la dejan en manos de bibliotecas de terceros para decidir cómo hacerlo. Es decir, no va a haber una implementación oficial en core python.
En lo que respecta a las implementaciones de terceros, hay algunos fragmentos (como http://code.activestate.com/recipes/572161/ ), que parecen hacer el trabajo bastante bien.
EDITAR:
Como nota, quiero mencionar que el comportamiento de verificación es preferible al tipo de comprobación, por lo tanto, creo que la comprobación de tipo estática no es una gran idea. Mi respuesta anterior está dirigida a responder la pregunta, no porque me escriba de esa manera.
El "tipado estático" en Python solo se puede implementar para que la verificación de tipos se realice en tiempo de ejecución, lo que significa que ralentiza la aplicación. Por lo tanto, no quiere eso como una generalidad. En su lugar, desea que algunos de sus métodos verifiquen sus entradas. Esto se puede hacer fácilmente con aseveraciones sencillas, o con decoradores si (erróneamente) cree que lo necesita mucho.
También hay una alternativa a la comprobación de tipos estática, y es utilizar una arquitectura de componentes orientada a aspectos como The Zope Component Architecture. En lugar de verificar el tipo, lo adaptas. Entonces, en lugar de:
assert isinstance(theobject, myclass)
tu hiciste esto:
theobject = IMyClass(theobject)
Si el objeto ya implementa IMyClass, no ocurre nada. Si no lo hace, se buscará un adaptador que envuelva lo que el objeto es a IMyClass, y se usará en lugar del objeto. Si no se encuentra un adaptador, se obtiene un error.
Esto combina el dinamismo de Python con el deseo de tener un tipo específico de una manera específica.
Esta no es una respuesta directa a la pregunta, pero descubrí un tenedor de Python que agrega tipado estático: mypy-lang.org , por supuesto, uno no puede confiar en él, ya que aún es un esfuerzo pequeño, pero interesante.