Можете ли вы перечислить аргументы ключевых слов, которые получает функция?

У меня есть 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 из списка допустимых аргументов ключевого слова, но мне было интересно: Есть ли способ программно перечислить аргументы ключевого слова, которые принимает конкретная функция?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
108
0
54 022
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

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

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 в своей подписи.

что, если я хочу распечатать только «ключевые слова» аргументы «ключи»?

Jia 15.10.2018 12:38

Расширение ответа 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)
Ответ принят как подходящий

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

>>> 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. Очевидно, что любая проверка времени выполнения на недопустимые значения в kwargs не может быть обнаружена.)

Хороший! Я не знал этой функции!

DzinX 13.10.2008 13:15

Учитывая, что метод, использующий объекты кода, более или менее идентичен, есть ли польза от необходимости импортировать еще один модуль ...?

jmetz 18.07.2014 13:21

@jmets - определенно - практически всегда лучше использовать библиотечный модуль, чем накатывать свой собственный. Кроме того, атрибуты объекта кода являются более внутренними и могут быть изменены (например, обратите внимание, что они перемещены в код в pyhon3). Использование модуля в качестве интерфейса дает вам дополнительную защиту на случай, если некоторые из этих внутренних компонентов когда-либо изменятся. Он также будет делать то, о чем вы, возможно, не думали, например, выдавать соответствующую ошибку типа для функций, которые вы не можете проверить (например, функции C).

Brian 19.08.2014 20:14

inspect.getargspec(f) устарел, начиная с Python 3.0; современный метод - inspect.signature(f).

gerrit 31.01.2017 21:30

К вашему сведению, если вы хотите поддерживать Cython и Python, этот метод не работает с функцией Cython'd. С другой стороны, опция co_varnames работает в обоих случаях.

partofthething 06.06.2017 02:00

Это очень полезно. Я понятия не имел о существовании inspect.

muammar 11.05.2019 01:12

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

Для решения 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']

и аналогично для позиционных переменных с использованием p.VAR_POSITIONAL и ключевого слова var с VAR_KEYWORD.

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

Другие вопросы по теме