将装饰器定义为类内的方法

M. *_* R. 4 python python-decorators

我试图在我的类中创建一个方法来计算特定函数的完整运行。我想使用一个简单的装饰器。我找到了这个参考并重写了这个简单的脚本:

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()
Run Code Online (Sandbox Code Playgroud)

当然,我得到:

TypeError: wrapper() missing 1 required positional argument: 'self'
Run Code Online (Sandbox Code Playgroud)

我尝试将计数器重写为类方法:

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)
Run Code Online (Sandbox Code Playgroud)

效果很好,但我认为这不是一个有效的装饰器定义。有什么方法可以在类方法中定义装饰器并将自参数传递给其函数吗?或者在类中定义装饰器是没有用的?

编辑:------ 首先,我无法在类方法之外定义装饰。其次,我试图创建一个预定的类,该类在固定的时间间隔和特定的时间内运行特定的函数(作为输入),因此我需要对其进行计数。

iam*_*rot 7

所以我可以为你起草一些东西,下面是代码:

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)
Run Code Online (Sandbox Code Playgroud)

为什么在类中使用装饰器会导致问题:

decorator function在课堂上建立一个内部并不是一件容易的事。原因如下:

原因 1 每个类方法都必须采用一个参数,self该参数instance是调用该函数的类的参数。现在,如果您让装饰器函数接受self参数,则装饰器调用@count将失败,因为它会转换为count()不传递self参数的函数,从而出现错误:

类型错误:wrapper() 缺少 1 个必需的位置参数:“self”

原因 2 现在为了避免这种情况,您可以decorator通过更改声明来使您的静态化,如下所示:

@staticmethod
def count(func):
    pass
Run Code Online (Sandbox Code Playgroud)

但随后你又遇到了另一个错误:

类型错误:“静态方法”对象不可调用

这意味着您也不能拥有静态方法。如果类中不能有静态方法,则必须将self实例传递给该方法,但如果将self实例传递给它,@count装饰器调用将不会传递该self实例,因此它将不起作用。

因此,这里有一个博客很好地解释了它、与之相关的问题以及替代方案。

我个人更喜欢使用 a 来helper class保存所有decorators可以使用的类,而不是定义它的唯一类。这将使您能够灵活地重用装饰器,而不是重新定义它们,这将遵循意识形态

编写一次代码,一遍又一遍地重复使用。