Durante il tentativo di scrivere un controllo di tipo minuscolo e offuscato, è stato scoperto un pattern di codice inaccettabile. Tuttavia, in modo non coerente non funziona correttamente. Questo è il codice che è stato scritto inizialmente per testarlo.TypeError: L'argomento function() dopo * deve essere una sequenza, non il generatore
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)
Quanto segue mostra una conversazione con l'interprete di Python e mette in evidenza l'errore che si presenta. Viene generato un numero TypeError
, ma non quello previsto. Mentre i generatori stavano bene, ora falliscono.
>>> 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 funzione statictypes
può essere riscritta, e la funzione isallinstance
ridefinito e avvolto. La soluzione più semplice è riscrivere il generatore in statictypes
per essere una lista di comprensione.
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)])))
Dopo di che, il isallinstance
sarà iniziare a lavorare come previsto una volta che è ricreato da zero. Il numero TypeError
che indica cosa c'è di sbagliato nel secondo argomento viene generato correttamente come desiderato.
>>> 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'>
Domande:
- Perché la prima funzione con il generatore somtimes lavoro e altre volte falliscono?
- Perché un generatore non è considerato una sequenza (poiché genera una sequenza)?
- Perché è necessaria una sequenza quando un generatore ovviamente funziona una volta?
Annuncio 1: guarda la riga in cui si verifica l'errore - non c'è nessuna chiamata 'isinstance()' in quella riga. –
OK, vedo - l'errore è riportato nella riga sbagliata, a causa del bug citato in 3. –
Ho lavorato con Python per circa 6 anni e non ho bisogno di controllo dei tipi. Questo era solo un esperimento per vedere quanto sarebbe stato possibile eseguire un piccolo tipo di controllo funzionale. Quasi nessuno sembra approfittare delle annotazioni delle funzioni, e questo sembrava un modo creativo per usarle. –