簡體   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