English 中文(简体)
python检查函数是否接受**kwargs
原标题:python check if function accepts **kwargs
  • 时间:2011-02-17 11:38:30
  •  标签:
  • 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是可以的,但<code>的FuncC错误得到了一个意外的关键字参数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扩展(和内置)中定义的函数可能很棘手,有时会以非常有创意的方式解释它们的参数。无法可靠地检测此类函数所期望的参数。请参阅函数的docstring和其他可读文档。

func是有问题的函数。

对于蟒蛇2,它是:

inspect.getargspec(func).keywords is not None

python3是一个小骗子,遵循https://www.python.org/dev/peps/pep-0362/参数的必须是VAR_KEYWORD

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

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

对于python>;3您应该使用inspect.getfullargspec

import inspect

def foo(**bar):
    pass

arg_spec = inspect.getfullargspec(foo)
assert arg_spec.varkw and 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])

More

获取方法采用的参数也是可能的:

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

官方文档中的描述可以找到此处

Examples

仅限位置

def foo(a, /): 
# the  /  enforces that all preceding parameters must be positional

foo(1) # valid
foo(a=1) #invalid

位置_或_关键字

def foo(a):
#  a  can be passed via position or keyword
# this is the default and most common parameter kind

变量_位置

def foo(*args):

KEYWORD_ONLY

def foo(*, a):
# the  *  enforces that all following parameters must by keyworded

foo(a=1) # valid
foo(1) # invalid

<code>VAR_KEYWORD</code>

def foo(**kwargs):

似乎您要检查函数是否接收到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是最好的方法,但您无法真正弄清楚是什么导致了TypeErrorTypeError

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

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

According to https://docs.python.org/2/reference/datamodel.html you should be able to test for use of **kwargs using 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

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





相关问题
Can Django models use MySQL functions?

Is there a way to force Django models to pass a field to a MySQL function every time the model data is read or loaded? To clarify what I mean in SQL, I want the Django model to produce something like ...

An enterprise scheduler for python (like quartz)

I am looking for an enterprise tasks scheduler for python, like quartz is for Java. Requirements: Persistent: if the process restarts or the machine restarts, then all the jobs must stay there and ...

How to remove unique, then duplicate dictionaries in a list?

Given the following list that contains some duplicate and some unique dictionaries, what is the best method to remove unique dictionaries first, then reduce the duplicate dictionaries to single ...

What is suggested seed value to use with random.seed()?

Simple enough question: I m using python random module to generate random integers. I want to know what is the suggested value to use with the random.seed() function? Currently I am letting this ...

How can I make the PyDev editor selectively ignore errors?

I m using PyDev under Eclipse to write some Jython code. I ve got numerous instances where I need to do something like this: import com.work.project.component.client.Interface.ISubInterface as ...

How do I profile `paster serve` s startup time?

Python s paster serve app.ini is taking longer than I would like to be ready for the first request. I know how to profile requests with middleware, but how do I profile the initialization time? I ...

Pragmatically adding give-aways/freebies to an online store

Our business currently has an online store and recently we ve been offering free specials to our customers. Right now, we simply display the special and give the buyer a notice stating we will add the ...

Converting Dictionary to List? [duplicate]

I m trying to convert a Python dictionary into a Python list, in order to perform some calculations. #My dictionary dict = {} dict[ Capital ]="London" dict[ Food ]="Fish&Chips" dict[ 2012 ]="...

热门标签