在对另一个问题的答案的评论中,有人说他们不确定functools.wraps
在做什么.所以,我问这个问题,以便在StackOverflow上有一个记录,供将来参考:究竟functools.wraps
做了什么?
假设我编写了一个装饰器来做一些非常通用的东西.例如,它可能会将所有参数转换为特定类型,执行日志记录,实现memoization等.
这是一个例子:
def args_as_ints(f):
def g(*args, **kwargs):
args = [int(x) for x in args]
kwargs = dict((k, int(v)) for k, v in kwargs.items())
return f(*args, **kwargs)
return g
@args_as_ints
def funny_function(x, y, z=3):
"""Computes x*y + 2*z"""
return x*y + 2*z
>>> funny_function("3", 4.0, z="5")
22
Run Code Online (Sandbox Code Playgroud)
到目前为止一切都很顺利.然而,有一个问题.装饰函数不保留原始函数的文档:
>>> help(funny_function)
Help on function g in module __main__:
g(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
幸运的是,有一个解决方法:
def args_as_ints(f):
def g(*args, **kwargs):
args = [int(x) for x in args]
kwargs = dict((k, int(v)) for k, v in kwargs.items()) …
Run Code Online (Sandbox Code Playgroud) 假设我有一个通用函数f.我想以编程方式创建一个与f相同的函数f2,但它具有自定义签名.
更多详情
给定列表l和字典d我希望能够:
即.假设我们有
l=["x", "y"]
d={"opt":None}
def f(*args, **kwargs):
#My code
Run Code Online (Sandbox Code Playgroud)
然后我想要一个带签名的函数:
def f2(x, y, opt=None):
#My code
Run Code Online (Sandbox Code Playgroud)
一个特定的用例
这只是我特定用例的简化版本.我只是以此为例.
我的实际用例(简化)如下.我们有一个通用的启动函数:
def generic_init(self,*args,**kwargs):
"""Function to initiate a generic object"""
for name, arg in zip(self.__init_args__,args):
setattr(self, name, arg)
for name, default in self.__init_kw_args__.items():
if name in kwargs:
setattr(self, name, kwargs[name])
else:
setattr(self, name, default)
Run Code Online (Sandbox Code Playgroud)
我们想在许多类中使用此函数.特别是,我们想要创建一个函数init,其行为类似于generic_init,但在创建时具有由某些类变量定义的签名:
class my_class:
__init_args__=["x", "y"]
__kw_init_args__={"my_opt": None}
__init__=create_initiation_function(my_class, generic_init)
setattr(myclass, "__init__", __init__)
Run Code Online (Sandbox Code Playgroud)
我们希望create_initiation_function创建一个新函数,其签名使用init_args和kw_init_args定义.可以写create_initiation_function吗?
请注意: …