116

我有一个字典,我需要将键/值作为关键字参数传递.. 例如..

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

这很好用,但是如果 d_args dict 中有函数不接受的example值,它显然会死掉。假设示例函数定义为def example(kw2):

这是一个问题,因为我不控制d_argsexample函数的生成。它们都来自外部模块,并且example只接受来自字典的一些关键字参数。

理想情况下我会做

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

我可能会从有效的关键字参数列表中过滤字典,但我想知道:有没有办法以编程方式列出特定函数采用的关键字参数?

4

6 回答 6

162

比直接检查代码对象并计算变量更好的是使用检查模块。

>>> 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 中的无效值。)

于 2008-10-13T09:02:23.973 回答
33

这将打印所有可传递参数的名称,关键字和非关键字:

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)

您现在可以使用已知 args 调用您的函数,但提取 kwargs,例如:

func(param1, param2, **getValidKwargs(func, kwargsDict))

这假设在其签名中func使用 no*args或magic。**kwargs

于 2008-10-13T08:09:15.390 回答
15

对于 Python 3 解决方案,您可以inspect.signature根据您想了解的参数类型使用和过滤。

使用带有位置或关键字、仅关键字、var 位置和 var 关键字参数的示例函数:

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 位置VAR_KEYWORD

此外,您可以在 if 中添加一个子句,通过检查 if p.defaultequals来检查是否存在默认值p.empty

于 2017-07-28T12:01:19.573 回答
9

在 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={})
于 2008-10-13T09:32:56.580 回答
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)
于 2008-10-13T08:20:20.657 回答
1

只需将其用于函数名称“myfun”:

myfun.__code__.co_varnames
于 2021-06-05T22:55:46.640 回答