我有以下功能:
def f(x, y):
print('x: %s' % x)
print('y: %s' % y)
我希望有一个包装器,如:
def g(**kwargs):
print('hello')
f(**kwargs)
print('world')
包装器g
是装饰器将返回的函数,因此它不能完全调用f
函数,而是调用具有任何参数列表的任何函数,因此这对于提供函数{ {1}} f
。
在定义**kwargs
函数之后,我想返回g
函数,但是从g
函数复制了参数列表,并且名称为f
函数。我在下面试过这个:
f
但是在调用import types
f_code = f.__code__
g_code = g.__code__
g.__code__ = types.CodeType(
f_code.co_argcount, g_code.co_nlocals,
g_code.co_stacksize, g_code.co_flags,
g_code.co_code, g_code.co_consts, g_code.co_names,
f_code.co_varnames, g_code.co_filename, f_code.co_name,
g_code.co_firstlineno, g_code.co_lnotab,
g_code.co_freevars, g_code.co_cellvars
)
函数后,我得到了分段错误。
我用谷歌搜索了如何以更高层次的方式解决这个问题,但我没有满足任何解决方案。我尝试了g
,但它没有更改参数列表,我尝试@functools.wraps
但它根本没有调用装饰器功能。也许你知道更好的解决方案吗?
更新
基本上下面有更多扩展示例:
@decorator.decorator
运行此程序失败,错误如下:
funcs = {}
def h(fi, *args, **kwargs):
def g(*args, **kwargs):
print('hello')
result = fi(**kwargs)
print('world')
return result
funcs[fi.func_code.co_name] = g
return g
@h
def f(x, y):
print('%s %s' % (x, y))
return 5
# z index is unneeded, so should be filtered
extended_arguments = {'x': 1, 'y': 2, 'z': 3}
func = funcs['f']
func_code = func.func_code
arguments = {
i: x for i, x in extended_arguments.items()
if x in func_code.co_varnames[:func_code.co_argcount]
}
func(**arguments)
这是我想要实施的确切案例。
尝试使用exec:
hello
Traceback (most recent call last):
File "x.py", line 26, in <module>
func(**arguments)
File "x.py", line 6, in g
result = fi(**kwargs)
TypeError: f() takes exactly 2 arguments (0 given)
产生以下错误:
funcs = {}
def h(fi, *args, **kwargs):
fi_code = fi.func_code
exec(
'''
def g(%s*args, **kwargs):
print('hello')
result = fi(**kwargs)
print('world')
return result
''' % ''.join(
'%s, ' % varname
for varname in fi_code.co_varnames[:fi_code.co_argcount]
)
)
funcs[fi_code.co_name] = g
return g
@h
def f(x, y):
print('%s %s' % (x, y))
return 5
# z index is unneeded, so should be filtered
extended_arguments = {'x': 1, 'y': 2, 'z': 3}
func = funcs['f']
func_code = func.func_code
arguments = {
i: x for i, x in extended_arguments.items()
if i in func_code.co_varnames[:func_code.co_argcount]
}
func(**arguments)