Ottima domanda. Ho appena avuto il problema che volevo scrivere una funzione che accetta un argomento di callback. A seconda del numero di argomenti di tale callback, deve essere chiamato diversamente.
Ho iniziato con la risposta di gimel, quindi mi sono espanso per poter gestire i builtin che non reagiscono bene con il modulo inspect
(raise TypeError
).
Quindi, ecco il codice per verificare se una funzione si aspetta esattamente un argomento:
def func_has_one_arg_only(func, typical_argument=None, ignore_varargs=False):
"""True if given func expects only one argument
Example (testbench):
assert not func_has_one_arg_only(dict.__getitem__), 'builtin 2 args'
assert func_has_one_arg_only(lambda k: k), 'lambda 1 arg'
assert not func_has_one_arg_only(lambda k,x: k), 'lambda 2 args'
assert not func_has_one_arg_only(lambda *a: k), 'lambda *a'
assert not func_has_one_arg_only(lambda **a: k), 'lambda **a'
assert not func_has_one_arg_only(lambda k,**a: k), 'lambda k,**a'
assert not func_has_one_arg_only(lambda k,*a: k), 'lambda k,*a'
assert func_has_one_arg_only(lambda k: k, ignore_varargs=True), 'lambda 1 arg'
assert not func_has_one_arg_only(lambda k,x: k, ignore_varargs=True), 'lambda 2 args'
assert not func_has_one_arg_only(lambda *a: k, ignore_varargs=True), 'lambda *a'
assert not func_has_one_arg_only(lambda **a: k, ignore_varargs=True), 'lambda **a'
assert func_has_one_arg_only(lambda k,**a: k, ignore_varargs=True), 'lambda k,**a'
assert func_has_one_arg_only(lambda k,*a: k, ignore_varargs=True), 'lambda k,*a'
"""
try:
import inspect
argspec = inspect.getargspec(func)
except TypeError: # built-in c-code (e.g. dict.__getitem__)
try:
func(typical_argument)
except TypeError:
return False
else:
return True
else:
if not ignore_varargs:
if argspec.varargs or argspec.keywords:
return False
if 1 == len(argspec.args):
return True
return False
raise RuntimeError('This line should not be reached')
È possibile controllare il comportamento relative al varargs argomenti *args
e **kwargs
con il parametro ignore_varargs
.
Il parametro typical_argument
è un kludge: se inspect
non riesce a funzionare, ad es. sui builtin sopracitati, quindi proviamo a chiamare la funzione con un argomento e vediamo cosa succede.
Il problema con questo approccio è che ci sono più motivi per raise TypeError
: viene utilizzato il numero errato di argomenti o viene utilizzato il tipo di argomenti errato. Consentendo all'utente di fornire un typical_argument
sto tentando di aggirare questo problema.
Questo non è bello. Ma può aiutare la gente a fare la stessa domanda e anche a correre sul fatto che inspect
non è in grado di ispezionare le implementazioni di funzioni con codice C. Forse la gente ha un suggerimento migliore?
Grazie Ho appena scoperto che molto funzione come hai postato quella risposta. Questo è esattamente quello di cui ho bisogno. – tomeedee
Anche perché non ho il rep per modificare la tua risposta hai errore nella tua risposta è getargspec() not getspspect() – tomeedee
Dovresti usare inspect.getfullargspec (func) (http://docs.python.org/3.1/ library/inspect.html # inspect.getfullargspec) per Python 3.x – Casebash