¡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 agrega un entero y un diccionario, es probable que haya cometido un error obvio (y si quiere decir algo razonable, todavía es mejor que explícito que implícito).
Pero en la vida real a menudo se mezclan cantidades del mismo tipo equipo como se ve por el compilador, pero claramente diferente tipo humano, por ejemplo, el siguiente fragmento contiene un error evidente:
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 humana debería ver inmediatamente un error en la línea anterior siempre que conozca el 'tipo humano' de las variables height
y length
aunque parezca que la computadora es perfectamente legal multiplicación de int
y float
.
Hay más que se puede decir acerca de las posibles soluciones a este problema, pero la aplicación de "tipos de ordenador es, al parecer una solución de la mitad, 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 excelente. Hay más en el informativo post of Joel Spolsky.
Ahora bien, si alguien fue implementar algún tipo de biblioteca de terceros Pythonic que asignar automáticamente a los datos del mundo real su tipo humano y luego se encargó de transformar ese tipo como width * height -> area
y hacer cumplir el registro de entrada con función anotaciones, ¡Creo que sería un tipo de control que la gente realmente podría usar!
Y esto es lo que acabo de escribir sobre los peligros del tipado fuerte: http://stackoverflow.com/questions/1251791/what-are-the-limits-of-type-checking-and-type-systems/1276675#1276675 –
What si Bob tuvo que pintar un metro cuadrado de su habitación con pintura roja por cada módulo que importa? –
Luego deberías usar un cast de tipo explícito para castigar a Bob. Todos los sistemas de mecanografía fuerte, ya sean estáticos o dinámicos, tienen disposiciones para los tipos de conversión: p. ''cadena '+ 5' está prohibida, pero''cadena' + str (5) 'está bien. –