如何将这两个类装饰器与functools.update_包装?

2024-10-03 21:28:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我在阅读decorators,并试图将这两个示例混合起来,使它们成为类decorator而不是常规函数。第一种方法只允许每个参数运行一次函数,第二种方法计算运行该函数的次数。它们都很好地分开工作,但是当我试图同时用它们来装饰一个简单的函数时,它失败了。。。或者不是真的失败,而是打印出意外的错误结果。我读了一些书,发现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)

Tags: 方法函数selfhellodefargsupdatedecorator
1条回答
网友
1楼 · 发布于 2024-10-03 21:28:53

默认情况下,update_wrapper更新包装类中的__dict__。因此,Memoize中的funcCallCounter中的func覆盖,这意味着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'>

您可以通过执行以下操作来解决此问题:

^{pr2}$

它不会将__dict__CallCounter复制到Memoize实例,但仍然会复制{},依此类推

要访问CallCounter类,您需要:

print(doubleprint.__wrapped__.calls)

但您需要上面的修复程序,否则它将始终打印0(因为它从未被调用)。在

相关问题 更多 >