python检查函数是否接受**kwargs
是否有方法在调用函数之前检查函数是否接受**kwargs,例如python检查函数是否接受**kwargs,python,Python,是否有方法在调用函数之前检查函数是否接受**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错误得到了一个意外的关键字参数“
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错误得到了一个意外的关键字参数“id”
,因为它不接受任何参数
try:
f(**kwargs)
except TypeError:
#do stuff
是的
这只适用于Python函数。在C扩展(和内置)中定义的函数可能很棘手,有时会以非常有创意的方式解释它们的参数。无法可靠地检测此类函数所期望的参数。请参阅函数的docstring和其他人类可读文档。您似乎想检查函数是否接收到“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
的原因。例如,这仍然会引发类型错误
:
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'})
我的建议是尝试通过另一种机制来确定这些功能。例如,使用方法而不是函数传递对象,并仅调用具有特定方法的对象。或向对象或函数本身添加标志。根据
您应该能够使用co_标志测试**kwargs
的使用情况:
>>> 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
不过,正如参考文献中所指出的,这可能会在将来发生变化,因此我建议您一定要格外小心。一定要添加一些单元测试来检查此功能是否仍然存在。func
是有问题的函数
对于python2,它是:
inspect.getargspec(func).keywords is not None
python3有点诡计多端,参数的kind
后面必须是VAR\u关键字
def foo(a):
# 'a' can be passed via position or keyword
# this is the default and most common parameter kind
def foo(**kwargs):
Parameter.VAR_关键字-不绑定到任何其他参数的关键字参数的dict。这对应于Python函数定义中的“**kwargs”参数
对于python>3,您应该使用
导入检查
def foo(**巴):
通过
arg_spec=inspect.getfullargspec(foo)
断言arg_spec.varkw和arg_spec.varkw=='bar'
看到这个帖子中有很多不同的答案,我想我会用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>]
可以在官方文件中找到说明
例子
POSITIONAL\u仅限
def foo(a, /):
# the '/' enforces that all preceding parameters must be positional
foo(1) # valid
foo(a=1) #invalid
def foo(*, a):
# the '*' enforces that all following parameters must by keyworded
foo(a=1) # valid
foo(1) # invalid
POSITIONAL\u或\u关键字
def foo(a):
# 'a' can be passed via position or keyword
# this is the default and most common parameter kind
def foo(**kwargs):
VAR\u POSITIONAL
def foo(*args):
仅限关键字
def foo(a, /):
# the '/' enforces that all preceding parameters must be positional
foo(1) # valid
foo(a=1) #invalid
def foo(*, a):
# the '*' enforces that all following parameters must by keyworded
foo(a=1) # valid
foo(1) # invalid
VAR\u关键字
def foo(a):
# 'a' can be passed via position or keyword
# this is the default and most common parameter kind
def foo(**kwargs):
“请求原谅比允许更容易”+1是的,应该是,修好了。干杯。抱歉,不行。如果您制作的是**kwargs
正确,这将适用于任何非内置函数def foo(x):返回x
然后foo(**{x':1})
。这样就完成了任务,但我忍不住觉得它很危险。如果您的函数在代码中的任何位置抛出一个TypeError
,则无法从该代码段中知道TypeError
是传递无效的kwargs
还是逻辑中的错误。此解决方案的问题是您无法区分“参数绑定”TypeError和f抛出的TypeError。如果您使用的是检查,那么最好使用关键字参数的名称是不相关的,并且您没有检查命名参数varkw不是None,或者args中的“id”应该是它的样子。是的,名称不相关。存在是相关的。尝试在没有**kwarg的情况下检查功能VARW
将为None
。我想您应该使用实际的解释器来检查代码示例。如果只是存在不相关,为什么要给出一个检查名称的示例?EAFP在很多方面都很好,但是如果您“盲目”运行函数,而不知道其确切签名,而不进行检查,这个答案更可靠。inspect.getargspec()在Python 3.0中被弃用,请使用inspect.signature()或inspect.getfullargspec()代替它。如果函数是否接受kwargs非常重要,为什么您还不知道呢?如果它不是特别重要,那么就按照建议尝试一下。我在参考资料中没有看到任何东西说它将来可能会改变,甚至没有说它是特定于实现的。我看到的最接近警告注释的是:“co_标志中的其他位保留供内部使用。”