Su Python 3.3, è possibile utilizzare le annotazioni delle funzioni e ispezionare:
import inspect
def validate(f):
def wrapper(*args):
fname = f.__name__
fsig = inspect.signature(f)
vars = ', '.join('{}={}'.format(*pair) for pair in zip(fsig.parameters, args))
params={k:v for k,v in zip(fsig.parameters, args)}
print('wrapped call to {}({})'.format(fname, params))
for k, v in fsig.parameters.items():
p=params[k]
msg='call to {}({}): {} failed {})'.format(fname, vars, k, v.annotation.__name__)
assert v.annotation(params[k]), msg
ret = f(*args)
print(' returning {} with annotation: "{}"'.format(ret, fsig.return_annotation))
return ret
return wrapper
@validate
def xXy(x: lambda _x: 10<_x<100, y: lambda _y: isinstance(_y,float)) -> ('x times y','in X and Y units'):
return x*y
xy = xXy(10,3)
print(xy)
Se c'è un errore di convalida, stampe:
AssertionError: call to xXy(x=12, y=3): y failed <lambda>)
Se non c'è un errore di convalida, stampe:
wrapped call to xXy({'y': 3.0, 'x': 12})
returning 36.0 with annotation: "('x times y', 'in X and Y units')"
È possibile utilizzare una funzione piuttosto che una lambda a ottenere un nome nel fallimento dell'asserzione.
Come una nota, che in genere è davvero una cattiva idea - va contro il chicco di Python. Digitare il controllo è una brutta cosa in quasi tutti i casi. Vale anche la pena notare che potrebbe essere più sensato usare le annotazioni degli argomenti per farlo se si è in 3.x. –
@Lattyware: l'applicazione degli argomenti delle funzioni e dei tipi restituiti è uno degli esempi in [l'originale pep per decoratori] (http://www.python.org/dev/peps/pep-0318/) – jfs
Qual è la tua domanda? –