Excelente pregunta. Acabo de tener el problema de que quería escribir una función que toma un argumento de devolución de llamada. Dependiendo de la cantidad de argumentos de esa devolución de llamada, debe llamarse de manera diferente.
Comencé con la respuesta de gimel, luego expandí para poder tratar con edificaciones que no reaccionan bien con el módulo inspect
(raise TypeError
).
Así que aquí está el código para comprobar si una función de espera exactamente un argumento:
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')
Se puede controlar el comportamiento relacionado con varargs argumentos *args
y **kwargs
con el parámetro ignore_varargs
.
El parámetro typical_argument
es un kludge: Si inspect
no funciona, p. en las construcciones antes mencionadas, entonces tratamos de llamar a la función con un argumento y ver qué pasa.
El problema con este enfoque es que hay varias razones para raise TypeError
: Se usa el número de argumentos incorrecto o se usa un tipo de argumento incorrecto. Al permitir que el usuario proporcione un typical_argument
estoy tratando de eludir este problema.
Esto no es agradable. Pero puede ayudar a las personas que tienen la misma pregunta y también al hecho de que inspect
no pueden inspeccionar las implementaciones de funciones codificadas en C. Tal vez la gente tiene una mejor sugerencia?
Gracias Acabo de descubrir que muy función ya que publicaste esa respuesta. Eso es exactamente lo que necesito. – tomeedee
Además, dado que no tengo el representante para editar su respuesta, tiene un error tipográfico en su respuesta es getargspec() no getargspect() – tomeedee
Debe usar inspect.getfullargspec (func) (http://docs.python.org/3.1/ library/inspect.html # inspect.getfullargspec) para Python 3.x – Casebash