如何列出函数接收的关键字参数?
我有一个字典(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 个回答
如果你想在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
来实现。
这段代码会打印出所有可以传入的参数,包括关键字参数和非关键字参数:
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
这种特殊的写法。
比起直接查看代码对象和搞清楚变量,使用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
中无效值的运行时检查显然是无法检测到的。)