Отличный вопрос. У меня просто была проблема, что я хотел написать функцию, которая принимает аргумент обратного вызова. В зависимости от количества аргументов этого обратного вызова его нужно вызывать по-разному.
Я начал с ответа гимеля, затем расширился, чтобы иметь дело со встроенными, которые плохо реагируют с модулем inspect
(raise TypeError
).
Так вот код, чтобы проверить, если функция ожидает ровно один аргумента:
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')
Вы можете контролировать поведение, связанное с переменной длиной аргументов *args
и **kwargs
с параметром ignore_varargs
.
Параметр typical_argument
- это kludge: Если inspect
не работает, например. на вышеупомянутых встроенных, тогда мы просто пытаемся вызвать функцию с одним аргументом и посмотреть, что произойдет.
Проблема с этим подходом заключается в том, что существует множество причин для raise TypeError
: используется неправильное количество аргументов или используется неправильный тип аргументов. Позволив пользователю предоставить typical_argument
, я пытаюсь обойти эту проблему.
Это нехорошо. Но это может помочь людям, которые имеют один и тот же вопрос, а также сталкиваются с тем, что inspect
не может проверять реализации C-кодированных функций. Может быть, у людей есть лучшее предложение?
Спасибо Я только что обнаружил, что так как вы отправили этот ответ. Это именно то, что мне нужно. – tomeedee
Также, поскольку у меня нет ответа на редактирование вашего ответа, у вас есть опечатка в вашем ответе, это getargspec() not getargspect() – tomeedee
Должен использовать inspect.getfullargspec (func) (http://docs.python.org/3.1/ library/inspect.html # inspect.getfullargspec) для Python 3.x – Casebash