我正在编写一个装饰器,它需要在调用它正在装饰的函数之前调用其他函数。修饰的函数可能有位置参数,但修饰程序将调用的函数只能接受关键字参数。有没有人有一个方便的方法将位置参数转换为关键字参数?
我知道我可以获得修饰函数的变量名列表:
>>> def a(one, two=2):
... pass
>>> a.func_code.co_varnames
('one', 'two')但是我不知道如何区分什么是按位置传递的,什么是关键字。
我的装饰器看起来像这样:
class mydec(object):
def __init__(self, f, *args, **kwargs):
self.f = f
def __call__(self, *args, **kwargs):
hozer(**kwargs)
self.f(*args, **kwargs)除了比较kwargs和co_varnames,向kwargs添加任何不在其中的东西,并期待最好的结果之外,还有其他方法吗?
发布于 2009-05-07 07:37:01
注意-- co_varnames将包括局部变量和关键字。这可能无关紧要,因为zip会截断较短的序列,但是如果您传递了错误数量的参数,可能会导致混乱的错误消息。
使用func_code.co_varnames[:func_code.co_argcount]可以避免这种情况,但最好使用inspect模块。即:
import inspect
argnames, varargs, kwargs, defaults = inspect.getargspec(func)您可能还希望处理函数定义**kwargs或*args的情况(即使只是在与装饰器一起使用时引发异常)。如果设置了这些变量,则getargspec的第二个和第三个结果将返回它们的变量名,否则它们将为None。
发布于 2009-05-06 19:00:33
任何以位置传递的arg都将被传递给*args。任何作为关键字传递的arg都将被传递给**kwargs。如果您有位置参数、值和名称,则可以执行以下操作:
kwargs.update(dict(zip(myfunc.func_code.co_varnames, args)))将它们全部转换为关键字参数。
发布于 2013-10-23 15:31:19
如果您使用的是PythonPython2.7,inspect.getcallargs()会为您提供开箱即用的解决方案。您只需将修饰函数作为第一个参数传递给它,然后将其余的参数完全按照您计划调用它的方式传递。示例:
>>> def f(p1, p2, k1=None, k2=None, **kwargs):
... pass
>>> from inspect import getcallargs我计划使用f('p1', 'p2', 'p3', k2='k2', extra='kx1') (请注意,k1将作为p3进行位置传递),所以...
>>> call_args = getcallargs(f, 'p1', 'p2', 'p3', k2='k2', extra='kx1')
>>> call_args
{'p2': 'p2', 'k2': 'k2', 'k1': 'p3', 'p1': 'p1', 'kwargs': {'extra': 'kx1'}}如果你知道装饰的函数不会使用**kwargs,那么这个键就不会出现在字典中,你就完成了(我假设没有*args,因为这会打破所有东西都有名称的要求)。如果您有**kwargs,就像我在本例中一样,并希望将它们包含在其余的命名参数中,则需要多加一行:
>>> call_args.update(call_args.pop('kwargs'))
>>> call_args
{'p2': 'p2', 'k2': 'k2', 'k1': 'p3', 'p1': 'p1', 'extra': 'kx1'}更新:对于Python >= 3.3,请参阅inspect.Signature.bind()和相关的inspect.signature function,了解类似于inspect.getcallargs() (但比inspect.getcallargs()更健壮)的功能。
https://stackoverflow.com/questions/830937
复制相似问题