为了账号安全,请及时绑定邮箱和手机立即绑定

函数包装是做什么的?

函数包装是做什么的?

三国纷争 2019-07-03 18:50:22
函数包装是做什么的?在对此的评论中回答另一个问题有人说他们不确定functools.wraps在做什么。因此,我提出这个问题,以便在StackOverflow上有一个记录,供将来参考:functools.wraps真的吗?
查看完整描述

3 回答

?
慕勒3428872

TA贡献1848条经验 获得超6个赞

当您使用装饰器时,您将一个函数替换为另一个函数。换句话说,如果你有一个装饰师

def logged(func):
    def with_logging(*args, **kwargs):
        print(func.__name__ + " was called")
        return func(*args, **kwargs)
    return with_logging

当你说

@loggeddef f(x):
   """does some math"""
   return x + x * x

这和说

def f(x):
    """does some math"""
    return x + x * x
f = logged(f)

以及你的功能f将其替换为_LOGING函数。不幸的是,这意味着如果你说

print(f.__name__)

它会打印出来with_logging因为这是你新功能的名字。实际上,如果您查看docstringf,它将是空白的,因为with_logging没有docstring,所以您编写的docstring将不再存在。另外,如果您查看该函数的pydoc结果,它将不会被列为接受一个参数x相反,它将被列为*args**kwargs因为这就是日志记录所需要的。

如果使用装饰器总是意味着丢失有关函数的信息,那么这将是一个严重的问题。所以我们才有functools.wraps..这使用了一个在装饰器中使用的函数,并添加了对函数名、docstring、参数列表等进行复制的功能。wraps它本身就是一个装饰器,下面的代码做的是正确的事情:

from functools import wrapsdef logged(func):
    @wraps(func)
    def with_logging(*args, **kwargs):
        print(func.__name__ + " was called")
        return func(*args, **kwargs)
    return with_logging@loggeddef f(x):
   """does some math"""
   return x + x * xprint(f.__name__)  # prints 'f'print(f.__doc__)   # prints 'does some math'


查看完整回答
反对 回复 2019-07-03
?
倚天杖

TA贡献1828条经验 获得超3个赞

我经常使用类,而不是函数,作为我的装饰师。我在这方面遇到了一些问题,因为一个对象不会拥有函数所期望的所有相同的属性。例如,对象将不具有属性__name__..我对此有一个特定的问题,很难跟踪Django报告的错误“Object无属性”__name__“。不幸的是,对于类风格的装饰师,我不认为@PARY能够胜任这项工作。相反,我创建了一个基本的装饰类,如下所示:

class DecBase(object):
    func = None

    def __init__(self, func):
        self.__func = func    def __getattribute__(self, name):
        if name == "func":
            return super(DecBase, self).__getattribute__(name)

        return self.func.__getattribute__(name)

    def __setattr__(self, name, value):
        if name == "func":
            return super(DecBase, self).__setattr__(name, value)

        return self.func.__setattr__(name, value)

这个类代理所有属性调用正在被修饰的函数。因此,您现在可以创建一个简单的装饰器,检查是否指定了2个参数,如下所示:

class process_login(DecBase):
    def __call__(self, *args):
        if len(args) != 2:
            raise Exception("You can only specify two arguments")

        return self.func(*args)


查看完整回答
反对 回复 2019-07-03
  • 3 回答
  • 0 关注
  • 872 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信