保留修饰函数的签名

假设我写了一个装饰器,它做了一些非常普通的事情。例如,它可能将所有参数转换为特定类型、执行日志记录、实现备忘录化等

以下是一个例子:

def args\u as\u ints(f):
def g(*args,**kwargs):
args=[int(x)表示args中的x]
kwargs=kwargs.items()中k,v的dict((k,int(v))
返回f(*args,**kwargs)
返回g
@args_as_ints
函数(x,y,z=3):
“”“计算x*y+2*z”“”
返回x*y+2*z
&燃气轮机&燃气轮机&燃气轮机;有趣的功能(“3”,4.0,z=“5”)
22

到目前为止一切都很好。然而,有一个问题。修饰函数不保留原始函数的文档:

&gt&燃气轮机&燃气轮机;帮助(有趣的功能)
模块_________中功能g的帮助:
g(*args,**kwargs)

幸运的是,有一个解决办法:

def args\u as\u ints(f):
def g(*args,**kwargs):
args=[int(x)表示args中的x]
kwargs=kwargs.items()中k,v的dict((k,int(v))
返回f(*args,**kwargs)
g、 _u_名称_=f.__名称__
g、 _uuu文件uuu=f.uuu文件__
返回g
@args_as_ints
函数(x,y,z=3):
“”“计算x*y+2*z”“”
返回x*y+2*z

这一次,函数名和文档是正确的:

&gt&燃气轮机&燃气轮机;帮助(有趣的功能)
有关模块\uuuu main\uuuu中的函数funcy\u函数的帮助:
有趣的函数(*args,**kwargs)
计算x*y+2*z

但仍然存在一个问题:函数签名是错误的。信息“*args,**kwargs”几乎毫无用处

怎么办?我可以想出两个简单但有缺陷的解决办法:

1–在docstring中包含正确的签名:

def funcy_函数(x,y,z=3):
“”“有趣的\u函数(x,y,z=3)——计算x*y+2*z”“”
返回x*y+2*z

这是不好的,因为重复。签名仍不会正确显示在自动生成的文档中。很容易更新函数,忘记更改docstring,或者输入错误。[是的,我知道docstring已经复制了函数体。请忽略这一点;有趣的函数只是一个随机示例。]

2–不要使用装饰器,或对每个特定签名使用专用装饰器:

def funcy\u functions\u decorator(f):
def g(x,y,z=3):
返回f(int(x),int(y),z=int(z))
g、 _u_名称_=f.__名称__
g、 _uuu文件uuu=f.uuu文件__
返回g

对于一组具有相同签名的函数来说,这是很好的,但一般来说是无用的。正如我在开始时所说,我希望能够完全通用地使用装饰器

我正在寻找一个完全通用、自动的解决方案

所以问题是:有没有一种方法可以在创建修饰函数签名后编辑它

否则,我是否可以编写一个decorator来提取函数签名,并在构造修饰函数时使用该信息而不是“*kwargs,**kwargs”?如何提取这些信息?我应该如何构造修饰函数——使用exec

还有其他方法吗

  1. 安装装饰器模块:

    $pip安装装饰器
    
  2. args\u的定义改为\u ints()

    导入装饰器
    @装饰工
    定义参数作为输入(f,*args,**kwargs):
    args=[int(x)表示args中的x]
    kwargs=kwargs.items()中k,v的dict((k,int(v))
    返回f(*args,**kwargs)
    @args_as_ints
    函数(x,y,z=3):
    “”“计算x*y+2*z”“”
    返回x*y+2*z
    打印功能(“3”,4.0,z=“5”)
    # 22
    帮助(有趣的功能)
    #有关模块\uuuu main\uuuu中的函数funcy\u函数的帮助:
    #
    #有趣的函数(x,y,z=3)
    #计算x*y+2*z


Python 3.4+

stdlib中的functools.wrapps()保留自Python 3.4以来的签名:

导入工具
def args_as_ints(func):
@functools.wrapps(func)
def包装(*args,**kwargs):
args=[int(x)表示args中的x]
kwargs=kwargs.items()中k,v的dict((k,int(v))
返回函数(*args,**kwargs)
返回包装器
@args_as_ints
函数(x,y,z=3):
“”“计算x*y+2*z”“”
返回x*y+2*z
打印(有趣的功能(“3”,4.0,z=“5”))
# 22
帮助(有趣的功能)
#有关模块\uuuu main\uuuu中的函数funcy\u函数的帮助:
#
#有趣的函数(x,y,z=3)
#计算x*y+2*z

functools.wrapps()至少从Python 2.5开始提供,但它不保留签名:

帮助(有趣的功能)
#有关模块\uuuu main\uuuu中的函数funcy\u函数的帮助:
#
#有趣的函数(*args,**kwargs)
#计算x*y+2*z

注意:*args,**kwargs而不是x,y,z=3

发表评论