Al intentar escribir un comprobador de tipo diminuto y ofuscado, se descubrió un patrón de código inaceptable. Sin embargo, falla de manera incoherente para funcionar correctamente. Este es el código que fue escrito inicialmente para probarlo.TypeError: function() El argumento después de * debe ser una secuencia, no el generador
def statictypes(a):
def b(a, b, c):
if b in a and not isinstance(c, a[b]): raise TypeError('{} should be {}, not {}'.format(b, a[b], type(c)))
return c
return __import__('functools').wraps(a)(lambda *c: b(a.__annotations__, 'return', a(*(b(a.__annotations__, *d) for d in zip(a.__code__.co_varnames, c)))))
@statictypes
def isallinstance(iterable: object, class_or_type_or_tuple: (type, tuple)) -> bool:
"""isallinstance(iterable, class_or_type_or_tuple) -> bool
Return whether all items in an iterable are instances of a class or of a
subclass thereof. With a type as second argument, return whether that is
all items' type. The form using a tuple, isallinstance(x, (A, B, ...)),
is a shortcut for any(isallinstance(x, y) for y in (A, B, ...)).
"""
return all(isinstance(item, class_or_type_or_tuple) for item in iterable)
A continuación, se muestra una conversación con el intérprete de Python y se resalta el error que aparece. Se genera un TypeError
, pero no el que se esperaba. Mientras que los generadores estaban bien, ahora fallan.
>>> isallinstance(range(1000000), int)
True
>>> isallinstance(range(1000000), (int, float))
True
>>> isallinstance(range(1000000), [int, float])
Traceback (most recent call last):
File "<pyshell#26>", line 1, in <module>
isallinstance(range(1000000), [int, float])
File "C:\Users\schappell\Downloads\test.py", line 5, in <lambda>
return __import__('functools').wraps(a)(lambda *c: b(a.__annotations__, 'return', a(*(b(a.__annotations__, *d) for d in zip(a.__code__.co_varnames, c)))))
TypeError: isallinstance() argument after * must be a sequence, not generator
La función statictypes
puede reescribirse, y la función isallinstance
redefinió y envuelto. La solución más simple es reescribir la generatior en statictypes
para que sea una lista de comprensión.
def statictypes(a):
def b(a, b, c):
if b in a and not isinstance(c, a[b]): raise TypeError('{} should be {}, not {}'.format(b, a[b], type(c)))
return c
return __import__('functools').wraps(a)(lambda *c: b(a.__annotations__, 'return', a(*[b(a.__annotations__, *d) for d in zip(a.__code__.co_varnames, c)])))
Después de eso, el isallinstance
habrá de empezar a trabajar como se esperaba, una vez que se vuelve a crear desde cero. El TypeError
indicando que estaba mal con el segundo argumento se genera correctamente como se deseó.
>>> isallinstance(range(1000000), int)
True
>>> isallinstance(range(1000000), (int, float))
True
>>> isallinstance(range(1000000), [int, float])
Traceback (most recent call last):
File "<pyshell#29>", line 1, in <module>
isallinstance(range(1000000), [int, float])
File "C:\Users\schappell\Downloads\test.py", line 5, in <lambda>
return __import__('functools').wraps(a)(lambda *c: b(a.__annotations__, 'return', a(*[b(a.__annotations__, *d) for d in zip(a.__code__.co_varnames, c)])))
File "C:\Users\schappell\Downloads\test.py", line 5, in <listcomp>
return __import__('functools').wraps(a)(lambda *c: b(a.__annotations__, 'return', a(*[b(a.__annotations__, *d) for d in zip(a.__code__.co_varnames, c)])))
File "C:\Users\schappell\Downloads\test.py", line 3, in b
if b in a and not isinstance(c, a[b]): raise TypeError('{} should be {}, not {}'.format(b, a[b], type(c)))
TypeError: class_or_type_or_tuple should be (<class 'type'>, <class 'tuple'>), not <class 'list'>
Preguntas:
- ¿Por qué la primera función con el generador somtimes trabajo y otras veces fallan?
- ¿Por qué un generador no se considera una secuencia (ya que genera una secuencia)?
- ¿Por qué se necesita una secuencia cuando un generador obviamente funciona algunas veces?
Anuncio 1 .: Observe la línea en la que se produce el error - no hay llamada 'issinstance()' en esa línea. –
Bien, veo - el error se informa en la línea incorrecta, debido al error mencionado en 3. –
He estado trabajando con Python durante aproximadamente 6 años y no necesito verificación de tipo. Este fue solo un experimento para ver qué tan pequeño podría ser un verificador de tipos funcional. Casi nadie parece estar aprovechando las anotaciones de funciones, y esto parecía una forma creativa de usarlas. –