有没有办法在调用之前检查函数是否接受** kwargs,例如
def FuncA(**kwargs):
print 'ok'
def FuncB(id = None):
print 'ok'
def FuncC():
print 'ok'
args = {'id': '1'}
FuncA(**args)
FuncB(**args)
FuncC(**args)
当我运行这个FuncA并且FuncB没问题但FuncC错误got an unexpected keyword argument 'id'
因为它不接受任何参数
答案 0 :(得分:15)
try:
f(**kwargs)
except TypeError:
#do stuff
答案 1 :(得分:8)
def foo(a, b, **kwargs):
pass
import inspect
args, varargs, varkw, defaults = inspect.getargspec(foo)
assert(varkw=='kwargs')
这仅适用于Python函数。在C扩展(和内置函数)中定义的函数可能很棘手,有时会以非常有创意的方式解释它们的参数。没有办法可靠地检测出这些函数所期望的参数。请参阅函数的docstring和其他人类可读的文档。
答案 2 :(得分:4)
func
是有问题的功能。
使用python2,它是:
inspect.getargspec(func).keywords is not None
python3有点转向,https://www.python.org/dev/peps/pep-0362/后kind
参数必须为VAR_KEYWORD
Parameter.VAR_KEYWORD - 不与任何其他参数绑定的关键字参数的字典。这对应于" ** kwargs" Python函数定义中的参数。
any(param for param in inspect.signature(func).parameters.values() if param.kind == param.VAR_KEYWORD)
答案 3 :(得分:1)
您似乎想检查该函数是否收到'id'关键字参数。你不能通过检查真正做到这一点,因为函数可能不是一个正常的函数,或者你可能有这样的情况:
def f(*args, **kwargs):
return h(*args, **kwargs)
g = lambda *a, **kw: h(*a, **kw)
def h(arg1=0, arg2=2):
pass
f(id=3)
仍然失败
按照建议捕获TypeError
是最好的方法,但你无法弄清楚导致TypeError
的原因。例如,这仍然会引发TypeError
:
def f(id=None):
return "%d" % id
f(**{'id': '5'})
这可能是您要调试的错误。如果您正在进行检查以避免该功能的某些副作用,如果您抓住它,它们可能仍然存在。例如:
class A(object):
def __init__(self): self._items = set([1,2,3])
def f(self, id): return self._items.pop() + id
a = A()
a.f(**{'id': '5'})
我的建议是尝试通过其他机制识别功能。例如,使用方法而不是函数传递对象,并仅调用具有特定方法的对象。或者为对象或函数本身添加一个标志。
答案 4 :(得分:1)
根据https://docs.python.org/2/reference/datamodel.html
您应该可以使用**kwargs
co_flags
的使用情况
>>> def blah(a, b, kwargs):
... pass
>>> def blah2(a, b, **kwargs):
... pass
>>> (blah.func_code.co_flags & 0x08) != 0
False
>>> (blah2.func_code.co_flags & 0x08) != 0
True
虽然如参考文献中所述,未来可能会有所改变,但我绝对会建议您格外小心。绝对添加一些单元测试来检查此功能是否仍然存在。
答案 5 :(得分:1)
对于python> 3,您应该使用inspect.getfullargspec。
import inspect
def foo(**bar):
pass
arg_spec = inspect.getfullargspec(foo)
assert arg_spec.varkw and arg_spec.varkw == 'bar'
答案 6 :(得分:1)
看到这个线程中有很多不同的答案,我想我会用inspect.signature()
来给我两分钱。
假设您具有此方法:
def foo(**kwargs):
您可以测试此方法的签名中是否包含**kwargs
:
import inspect
sig = inspect.signature(foo)
params = sig.parameters.values()
has_kwargs = any([True for p in params if p.kind == p.VAR_KEYWORD])
也可以获取方法所使用的参数:
import inspect
sig = inspect.signature(foo)
params = sig.parameters.values()
for param in params:
print(param.kind)
您还可以将它们存储在这样的变量中:
kinds = [param.kind for param in params]
# [<_ParameterKind.VAR_KEYWORD: 4>]
除了关键字参数之外,总共还有5种参数种类,如下所示:
POSITIONAL_ONLY # parameters must be positional
POSITIONAL_OR_KEYWORD # parameters can be positional or keyworded (default)
VAR_POSITIONAL # *args
KEYWORD_ONLY # parameters must be keyworded
VAR_KEYWORD # **kwargs
可以在here中找到官方文档中的描述。
POSITIONAL_ONLY
def foo(a, /):
# the '/' enforces that all preceding parameters must be positional
foo(1) # valid
foo(a=1) #invalid
POSITIONAL_OR_KEYWORD
def foo(a):
# 'a' can be passed via position or keyword
# this is the default and most common parameter kind
VAR_POSITIONAL
def foo(*args):
KEYWORD_ONLY
def foo(*, a):
# the '*' enforces that all following parameters must by keyworded
foo(a=1) # valid
foo(1) # invalid
VAR_KEYWORD
def foo(**kwargs):