繁体   English   中英

python检查函数是否接受**kwargs

[英]python check if function accepts **kwargs

有没有办法在调用一个函数之前检查它是否接受 **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'因为它不接受任何参数

try:
    f(**kwargs)
except TypeError:
    #do stuff

请求原谅比允许更容易

def foo(a, b, **kwargs):
  pass

import inspect
args, varargs, varkw, defaults = inspect.getargspec(foo)
assert(varkw=='kwargs')

这仅适用于 Python 函数。 在 C 扩展(和内置)中定义的函数可能很棘手,有时会以非常有创意的方式解释它们的参数。 没有办法可靠地检测这些函数期望的参数。 请参阅函数的文档字符串和其他人类可读的文档。

func是有问题的函数。

使用python2,它是:

inspect.getargspec(func).keywords is not None

python3有点狡猾,跟随https://www.python.org/dev/peps/pep-0362/参数的kind必须是VAR_KEYWORD

Parameter.VAR_KEYWORD - 未绑定到任何其他参数的关键字参数的字典。 这对应于 Python 函数定义中的“**kwargs”参数。

any(param for param in inspect.signature(func).parameters.values() if param.kind == param.VAR_KEYWORD)

看到这个帖子中有很多不同的答案,我想我会使用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

官方文档中的描述可以在这里找到。

例子

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):

对于 python > 3,你应该使用inspect.getfullargspec

import inspect

def foo(**bar):
    pass

arg_spec = inspect.getfullargspec(foo)
assert arg_spec.varkw and arg_spec.varkw == 'bar'

根据https://docs.python.org/2/reference/datamodel.html,您应该能够使用co_flags测试**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

不过,正如参考资料中所指出的,这在未来可能会发生变化,所以我绝对建议要格外小心。 一定要添加一些单元测试来检查此功能是否仍然存在。

您似乎想检查该函数是否收到“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'})

我的建议是尝试通过另一种机制来识别功能。 例如,通过方法而不是函数传递对象,并且只调用具有特定方法的对象。 或者向对象或函数本身添加一个标志。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM