如何列出函数接收的关键字参数?

124 投票
7 回答
76846 浏览
提问于 2025-04-11 09:25

我有一个字典(dict),我需要把里面的键值对作为关键字参数传递给一个函数。比如说……

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

这样做是没问题的,但是如果这个字典里的某些值不被那个函数接受,就会出错。比如,如果这个函数是这样定义的:def example(kw2):

这就成了一个问题,因为我无法控制这个字典(d_args)的生成,也无法控制这个函数(example)。它们都是来自外部模块,而example只接受字典中的某些关键字参数……

理想情况下,我只想这样做:

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

我可能会从一个有效的关键字参数列表中筛选这个字典,但我在想:有没有办法程序化地列出一个特定函数接受的关键字参数?

7 个回答

19

如果你想在Python 3中解决这个问题,可以使用inspect.signature这个工具,然后根据你想了解的参数类型进行筛选。

这里有一个示例函数,它包含了位置参数、关键字参数、仅关键字参数、可变位置参数和可变关键字参数:

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_KEYWORD

另外,你还可以在条件语句中添加一个判断,来检查是否存在默认值,这可以通过判断p.default是否等于p.empty来实现。

35

这段代码会打印出所有可以传入的参数,包括关键字参数和非关键字参数:

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 get_valid_args(func, args_dict):
    '''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 args_dict.iteritems() 
                if key in validArgs)

然后你可以这样使用它:

>>> func(**get_valid_args(func, args))

如果你真的只需要函数的关键字参数,可以用 func_defaults 属性来提取它们:

def get_valid_kwargs(func, args_dict):
    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 args_dict.iteritems() 
                if key in validKwargs)

现在你可以用已知的参数来调用你的函数,但提取的关键字参数,比如:

func(param1, param2, **get_valid_kwargs(func, kwargs_dict))

这假设 func 的定义中没有使用 *args**kwargs 这种特殊的写法。

167

比起直接查看代码对象和搞清楚变量,使用inspect模块会更方便一些。

>>> import inspect
>>> def func(a,b,c=42, *args, **kwargs): pass
>>> inspect.getargspec(func)
(['a', 'b', 'c'], 'args', 'kwargs', (42,))

如果你想知道某个函数是否可以用一组特定的参数调用,你需要那些没有默认值的参数。这些参数可以通过以下方式获取:

def get_required_args(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 missing_args(func, argdict):
    return set(get_required_args(func)).difference(argdict)

同样地,要检查无效的参数,可以使用:

def invalid_args(func, argdict):
    args, varargs, varkw, defaults = inspect.getargspec(func)
    if varkw: return set()  # All accepted
    return set(argdict) - set(args)

所以,完整的检查一个函数是否可以调用的代码是:

def is_callable_with_args(func, argdict):
    return not missing_args(func, argdict) and not invalid_args(func, argdict)

(这只适用于Python的参数解析,任何对kwargs中无效值的运行时检查显然是无法检测到的。)

撰写回答