2008-10-13 3 views
81

У меня есть Dict, что мне нужно, чтобы передать ключ/значение в качестве ключевых аргументов .. Например ..Можете ли вы перечислить аргументы ключевых слов, получаемые функцией Python?

d_args = {'kw1': 'value1', 'kw2': 'value2'} 
example(**d_args) 

Это прекрасно работает, но если есть значения в d_args Словаре, которые не принимаются функцией example, он явно умирает .. Скажем, если пример функции определяется как def example(kw2):

Это проблема, так как я не контролируем ни поколение d_args, или функцию example .. Они оба приходят из внешних модулей, а example принимает только некоторые ключевые слова-аргументы fr О.М. ДИКТ ..

В идеале я бы просто сделать

parsed_kwargs = feedparser.parse(the_url) 
valid_kwargs = get_valid_kwargs(parsed_kwargs, valid_for = PyRSS2Gen.RSS2) 
PyRSS2Gen.RSS2(**valid_kwargs) 

Я, вероятно, просто фильтровать Dict, из списка допустимых ключевых слов-аргументов, но мне было интересно: Есть ли способ программно укажите аргументы ключевых слов, которые выполняет определенная функция?

ответ

114

немного лучше, чем Осмотрев объект кода непосредственно и разработка переменных является использование инспектировать модуля.

>>> 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. 

Тогда функция, чтобы сказать, что вам не хватает из вашего Словаря является:

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, очевидно, не могут быть обнаружены)

+0

Ницца! Я не знал этой функции! – DzinX 2008-10-13 09:15:25

28

Это напечатает имена всех проходимых аргументов, ключевое слово и те, без ключевого слова:

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)) 

EDIT: Небольшое дополнение: если вы действительно нужно только ключевые аргументы функции, вы можете использовать атрибут 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

Расширение ответ 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) 
6

В 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={}) 
0

Для решения Python 3, вы можете использовать inspect.signature и фильтр в соответствии с the kind of parameters вы хотите знать о.

Принимая функцию образца с позиционными или ключевым словом, ключевыми словами только, вар позиционных и варом ключевых словами параметров:

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.

Кроме того, вы можете добавить предложение в том случае, если проверить, существует ли значение по умолчанию, если проверка p.default равна p.empty.