我写了一个名为apply_first
的装饰器,它设置了装饰函数的第一个参数。不幸的是,这个装饰者有错误的签名。有什么方法吗?我通常使用decorator
来保留签名,但这一次,我想改变它。
def apply_first(x):
def decorate(f):
def g(*args):
return f(*((x,) + args))
return g
return decorate
@apply_first(5)
def add(x,y):
return x+y
print(add(3))
# prints 8
答案 0 :(得分:0)
更好的解决方案:
我最后写了一个装饰器来修复装饰第一个参数
的装饰器import decorator
import sys
def wrapper_string(pre_decor):
argspec = decorator.getfullargspec(pre_decor)
if len(argspec.args) == 0:
raise TypeError("Couldn't find a first argument to decorate away.")
allargs = list(argspec.args[1:])
allshortargs = list(argspec.args[1:])
if argspec.varargs:
allargs.append('*' + argspec.varargs)
allshortargs.append('*' + argspec.varargs)
elif argspec.kwonlyargs:
allargs.append('*') # single star syntax
for a in argspec.kwonlyargs:
allargs.append('%s=None' % a)
allshortargs.append('%s=%s' % (a, a))
if argspec.varkw:
allargs.append('**' + argspec.varkw)
allshortargs.append('**' + argspec.varkw)
head = "def " + pre_decor.__name__ + "(" + ', '.join(allargs) + "):"
body = " return _decorator_(_func_)("+ ', '.join(allshortargs) +")"
return head + "\n" + body
def update_signature(pre_decor, post_decor, **kw):
"Update the signature of post_decor with the data in pre_decor"
post_decor.__name__ = pre_decor.__name__
post_decor.__doc__ = getattr(pre_decor, '__doc__', None)
post_decor.__dict__ = getattr(pre_decor, '__dict__', {})
argspec = decorator.getfullargspec(pre_decor)
if len(argspec.args) == len(argspec.defaults):
pos = 1
else:
pos = 0
post_decor.__defaults__ = getattr(pre_decor, '__defaults__', ())[pos:]
post_decor.__kwdefaults__ = getattr(pre_decor, '__kwdefaults__', None)
#post_decor.__annotations__ = getattr(pre_decor, '__annotations__', None)
try:
frame = sys._getframe(3)
except AttributeError: # for IronPython and similar implementations
callermodule = '?'
else:
callermodule = frame.f_globals.get('__name__', '?')
post_decor.__module__ = getattr(pre_decor, '__module__', callermodule)
post_decor.__dict__.update(kw)
@decorator.decorator
def decorate_first_arg(dec, pre_decor):
evaldict = pre_decor.__globals__.copy()
evaldict['_decorator_'] = dec
evaldict['_func_'] = pre_decor
wrapper = compile(wrapper_string(pre_decor), "<string>", "single")
exec(wrapper, evaldict)
post_decor = evaldict[pre_decor.__name__]
update(pre_decor, post_decor)
return post_decor
几乎所有代码都是从Michele Simionato的decorator
模块(GitHub)中复制并进行了适当修改。
有了这个,上面的例子可以固定为:
@decorate_first_arg
def apply_first(x):
def decorate(f):
def g(*args):
return f(*((x,) + args))
return g
return decorate