繁体   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