Можете ли вы перечислить аргументы ключевых слов, получаемые функцией Python?
У меня есть dict, который мне нужно передать ключ/значения в качестве аргументов ключевого слова. Например..
d_args = {'kw1': 'value1', 'kw2': 'value2'}
example(**d_args)
Это отлично работает, но если в d_args dict есть значения, которые не принимаются функцией example
, они, очевидно, умирают. Скажем, если примерная функция определена как def example(kw2):
Это проблема, поскольку я не управляю генерацией функции d_args
или example
. Оба они поступают из внешних модулей, а example
принимает только некоторые ключевые слова-аргументы из dict..
В идеале я бы просто сделал
parsed_kwargs = feedparser.parse(the_url)
valid_kwargs = get_valid_kwargs(parsed_kwargs, valid_for = PyRSS2Gen.RSS2)
PyRSS2Gen.RSS2(**valid_kwargs)
Я, вероятно, просто отфильтрую dict из списка допустимых аргументов ключевого слова, но мне было интересно: Есть ли способ программно перечислить аргументы ключевых слов, которые выполняет определенная функция?
Ответы
Ответ 1
Немного лучше, чем просто проверять объект кода и разрабатывать переменные, использовать модуль проверки.
>>> import inspect
>>> def func(a,b,c=42, *args, **kwargs): pass
>>> inspect.getargspec(func)
(['a', 'b', 'c'], 'args', 'kwargs', (42,))
Если вы хотите узнать, может ли его вызываемый с определенным набором аргументов, вам нужны аргументы без заданного по умолчанию значения. Их можно получить:
def getRequiredArgs(func):
args, varargs, varkw, defaults = inspect.getargspec(func)
if defaults:
args = args[:-len(defaults)]
return args # *args and **kwargs are not required, so ignore them.
Затем функция, чтобы сообщить, чего вам не хватает в вашем конкретном dict:
def missingArgs(func, argdict):
return set(getRequiredArgs(func)).difference(argdict)
Аналогично, чтобы проверить недопустимые аргументы, используйте:
def invalidArgs(func, argdict):
args, varargs, varkw, defaults = inspect.getargspec(func)
if varkw: return set() # All accepted
return set(argdict) - set(args)
И поэтому полный тест, если он вызываемый:
def isCallableWithArgs(func, argdict):
return not missingArgs(func, argdict) and not invalidArgs(func, argdict)
(Это хорошо только при анализе python arg. Любые проверки времени выполнения для недопустимых значений в kwargs, очевидно, не могут быть обнаружены.)
Ответ 2
Здесь будут напечатаны имена всех пропущенных аргументов, ключевых слов и не связанных с ключевыми словами:
def func(one, two="value"):
y = one, two
return y
print func.func_code.co_varnames[:func.func_code.co_argcount]
Это связано с тем, что первые co_varnames
всегда являются параметрами (следующие локальные переменные, например y
в приведенном выше примере).
Итак, теперь у вас может быть функция:
def getValidArgs(func, argsDict):
'''Return dictionary without invalid function arguments.'''
validArgs = func.func_code.co_varnames[:func.func_code.co_argcount]
return dict((key, value) for key, value in argsDict.iteritems()
if key in validArgs)
Что вы могли бы использовать следующим образом:
>>> func(**getValidArgs(func, args))
РЕДАКТИРОВАТЬ: небольшое дополнение: если вам действительно нужны только аргументы ключевого слова, вы можете использовать атрибут func_defaults
, чтобы извлечь их:
def getValidKwargs(func, argsDict):
validArgs = func.func_code.co_varnames[:func.func_code.co_argcount]
kwargsLen = len(func.func_defaults) # number of keyword arguments
validKwargs = validArgs[-kwargsLen:] # because kwargs are last
return dict((key, value) for key, value in argsDict.iteritems()
if key in validKwargs)
Теперь вы можете вызывать свою функцию с известными аргументами, но извлекать kwargs, например:
func(param1, param2, **getValidKwargs(func, kwargsDict))
Это предполагает, что func
использует в своей сигнатуре магию *args
или **kwargs
.
Ответ 3
В Python 3.0:
>>> import inspect
>>> import fileinput
>>> print(inspect.getfullargspec(fileinput.input))
FullArgSpec(args=['files', 'inplace', 'backup', 'bufsize', 'mode', 'openhook'],
varargs=None, varkw=None, defaults=(None, 0, '', 0, 'r', None), kwonlyargs=[],
kwdefaults=None, annotations={})
Ответ 4
Расширение ответа DzinX:
argnames = example.func_code.co_varnames[:func.func_code.co_argcount]
args = dict((key, val) for key,val in d_args.iteritems() if key in argnames)
example(**args)
Ответ 5
Для решения Python 3 вы можете использовать inspect.signature
и фильтровать в соответствии с тип параметров, о котором вы хотели бы узнать.
Взятие примерной функции с параметрами positional или keyword, keyword-only, var positional и var keyword:
def spam(a, b=1, *args, c=2, **kwargs):
print(a, b, args, c, kwargs)
Вы можете создать для него объект подписи:
from inspect import signature
sig = signature(spam)
а затем фильтруйте со списком, чтобы узнать нужные детали:
>>> # positional or keyword
>>> [p.name for p in sig.parameters.values() if p.kind == p.POSITIONAL_OR_KEYWORD]
['a', 'b']
>>> # keyword only
>>> [p.name for p in sig.parameters.values() if p.kind == p.KEYWORD_ONLY]
['c']
и, аналогично, для позиций var с использованием p.VAR_POSITIONAL
и ключевого слова var с VAR_KEYWORD
.
Кроме того, вы можете добавить предложение в if, чтобы проверить, существует ли значение по умолчанию, если p.default
равно p.empty
.