簡體   English   中英

將裝飾器定義為 class 中的方法

[英]define a decorator as method inside class

我正在嘗試在我的 class 中創建一個方法來計算特定 function 的完整運行。我想使用一個簡單的裝飾器。 我找到了這個參考並重寫了這個簡單的腳本:

class myclass:
    def __init__(self):
        self.cnt = 0

    def counter(function):
        """
        this method counts the runtime of a function
        """
        def wrapper(self, **args):
            function(**args)
            self.counter += 1
        return wrapper


@myclass.counter
def somefunc():
    print("hello from somefunc")


if __name__ == "__main__":
    obj = myclass()
    # or if comment @myclass.counter
    # somefunc = myclass.counter(somefunc)
    somefunc()

當然,我得到:

TypeError: wrapper() missing 1 required positional argument: 'self'

我試圖將計數器重寫為 class 方法:

class myclass:
    def __init__(self):
        self.cnt = 0

    def counter(self, function):
        """
        this method counts the runtime of a function
        """
        def wrapper(**args):
            function(**args)
            self.cnt += 1
        return wrapper


def somefunc():
    print("hello from somefunc")


if __name__ == "__main__":
    obj = myclass()
    somefunc = obj.counter(somefunc)
    for i in range(10):
        somefunc()
        print(obj.cnt)

哪個工作正常但我認為它不是有效的裝飾器定義。 有什么方法可以在 class 方法中定義裝飾器並將自變量傳遞給它的 function 嗎? 或者在 class 中定義裝飾器是沒用的?

編輯:------- 首先,我無法在 class 方法之外定義裝飾。 其次,我正在嘗試制作一個預定的 class,它在固定的時間間隔和特定的時間內運行特定的 function(作為輸入),因此我需要計算它。

所以我可以為你起草一些東西,下面是代碼:

def count(func):
    def wrapper(self):
        TestClass.call_count += 1
        func(self)

    return wrapper


class TestClass(object):
    call_count = 0

    @count
    def hello(self):
        return 'hello'


if __name__ == '__main__':
    x = TestClass()
    for i in range(10):
        x.hello()

    print(TestClass.call_count)

為什么在 class 中使用裝飾器會導致問題:

decorator function並不直接。原因如下:

原因 1每個 class 方法都必須采用一個參數self ,它是 class 的instance ,通過它調用 function。 現在,如果你讓裝飾器 function 接受一個self參數,裝飾器調用@count將失敗,因為它被轉換為count() ,它不傳遞self參數,因此錯誤:

TypeError: wrapper() missing 1 required positional argument: 'self'

原因 2現在,為了避免您可以通過更改如下聲明,將decorator設置為 static:

@staticmethod
def count(func):
    pass

但是你有另一個錯誤:

TypeError: 'staticmethod' object 不可調用

這意味着您也不能擁有 static 方法。 如果在 class 中不能有 static 方法,則必須將self實例傳遞給該方法,但如果將self實例傳遞給它, @count裝飾器調用將不會傳遞self實例,因此它不會'不工作。

所以這里有一個博客很好地解釋了它,與之相關的問題以及替代方案是什么。

我個人更喜歡選擇有一個helper class來保存我所有可以使用的decorators ,而不是它定義的唯一 class。 這將使您可以靈活地重用裝飾器,而不是重新定義它們,這將遵循意識形態

一次編碼,一遍又一遍地重用。

您的第二個代碼示例在功能上等同於標准裝飾器。 標准裝飾器語法只是同一事物的簡寫,即重新分配等於閉包的 function 值(預定義為 arguments 的 function 指針),其中閉包是您的裝飾器包裝器,將原始值作為其預定義參數。

這是標准語法的等價物。 注意需要提前創建計數器 class 實例。 裝飾器語法引用該實例,因為它必須指示保存計數器的特定 object,而不僅僅是 object 的 class:

class myclass:
    def __init__(self):
        self.cnt = 0

    def counter(self,function):
        """
        this method counts the number of runtime of a function
        """
        def wrapper(**args):
            function(self,**args)
            self.cnt += 1
        return wrapper

global counter_object
counter_object = myclass()

@counter_object.counter
def somefunc(self):
    print("hello from somefunc")

if __name__ == "__main__":
    for i in range(10):
        somefunc()
        print(counter_object.cnt)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM