繁体   English   中英

如何将这两个类装饰器与functools.update_wrapper一起使用?

[英]How to use these two class decorators together with functools.update_wrapper?

我正在阅读有关装饰器的内容,并尝试将这两个示例混合在一起,并使它们成为类装饰器而不是常规函数。 第一个只允许你为每个参数运行一次函数,第二个只计算你运行该函数的次数。 它们都工作得很好但是当我尝试同时装饰一个简单的函数时它失败了......或者并没有真正失败但是会打印出意想不到的错误结果。 我做了一些阅读,发现functools模块可以帮助,但我不知道如何。

from functools import update_wrapper

class Memoize:
    def __init__(self, func):
        self.func = func
        self.memo = dict()
        update_wrapper(self, func)

    def __call__(self, *args):
        if args not in self.memo:
            self.memo[args] = self.func(args)
        else:
            print("cls decorator. You have printed this before")
        return self.memo[args]


class CallCounter:
    def __init__(self, func):
        self.func = func
        self.calls = 0
        self.__name__ = func.__name__
        update_wrapper(self, func)

    def __call__(self, *args, **kwargs):
        self.calls += 1
        return self.func(*args, **kwargs)


@Memoize
@CallCounter
def doubleprint(x):
    for elem in x:
        print(elem + " " + elem)


doubleprint('Hello')
doubleprint('Hello')
doubleprint('Hello')
doubleprint('Hello')
doubleprint('Bye')

print(doubleprint.calls)

doubleprint('Hello')

doubleprint('Hello')
doubleprint('Hello')
doubleprint('Hello')
doubleprint('Bye')

print(doubleprint.calls)

默认情况下update_wrapper更新__dict__从包裹类。 所以,你的funcMemoize被覆盖与funcCallCounter这意味着Memoize直接调用你的doubleprint()函数调用从未CallCounter

class Memoize:
    def __init__(self, func):
        self.func = func
        print(type(self.func))  # <class '__main__.CallCounter'>
        self.memo = dict()
        update_wrapper(self, func)
        print(type(self.func))  # <class 'function'>

您可以通过以下方式解决此问题

        update_wrapper(self, func, updated=[])

这不会将__dict__CallCounter复制到Memoize实例中,但仍会复制__name__, __doc__等。

要访问CallCounter类,您将:

print(doubleprint.__wrapped__.calls)

但是你需要上面的修复,否则它将始终打印0 (因为它永远不会被调用)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM