简体   繁体   English

将装饰器定义为 class 中的方法

[英]define a decorator as method inside class

I'm trying to create a method inside my class that counts the complete run of a specific function. I want to use a simple decorator.我正在尝试在我的 class 中创建一个方法来计算特定 function 的完整运行。我想使用一个简单的装饰器。 I found this reference and rewrite this simple script:我找到了这个参考并重写了这个简单的脚本:

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()

And of course, I get:当然,我得到:

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

I tried to rewrite the counter as a class method:我试图将计数器重写为 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)

Which works fine but I think it is not a valid decorator definition.哪个工作正常但我认为它不是有效的装饰器定义。 Is there any way to define the decorator inside the class method and pass the self-argument to its function?有什么方法可以在 class 方法中定义装饰器并将自变量传递给它的 function 吗? or defining a decorator inside a class is useless?或者在 class 中定义装饰器是没用的?

EDIT:------ First I can't define the decoration outside of the class method.编辑:------- 首先,我无法在 class 方法之外定义装饰。 Second I'm trying to make a scheduled class that runs a specific function (as input) for a fixed interval and a specific amount of time so I need to count it.其次,我正在尝试制作一个预定的 class,它在固定的时间间隔和特定的时间内运行特定的 function(作为输入),因此我需要计算它。

So I was able to draft up something for you, below is the code:所以我可以为你起草一些东西,下面是代码:

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)

Why would it cause problems to have the decorator in a class:为什么在 class 中使用装饰器会导致问题:

It's not straight forward to have a decorator function inside the class. The reasons are below:decorator function并不直接。原因如下:

Reason 1 Every class method must take an argument self which is the instance of the class through which the function is being called.原因 1每个 class 方法都必须采用一个参数self ,它是 class 的instance ,通过它调用 function。 Now if you make the decorator function take a self argument, the decorator call @count would fail as it get converted to count() which doesn't pass the self argument and hence the error:现在,如果你让装饰器 function 接受一个self参数,装饰器调用@count将失败,因为它被转换为count() ,它不传递self参数,因此错误:

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

Reason 2 Now to avoid that you can make your decorator as static by changing the declaration like below:原因 2现在,为了避免您可以通过更改如下声明,将decorator设置为 static:

@staticmethod
def count(func):
    pass

But then you have another error:但是你有另一个错误:

TypeError: 'staticmethod' object is not callable TypeError: 'staticmethod' object 不可调用

Which means you can't have a static method as well.这意味着您也不能拥有 static 方法。 If you can't have a static method in a class, you have to pass the self instance to the method but if you pass the self instance to it, the @count decorator call wouldn't pass the self instance and hence it won't work.如果在 class 中不能有 static 方法,则必须将self实例传递给该方法,但如果将self实例传递给它, @count装饰器调用将不会传递self实例,因此它不会'不工作。

So here is a blog that explains it quite well, the issues associated with it and what are the alternatives.所以这里有一个博客很好地解释了它,与之相关的问题以及替代方案是什么。

I personally prefer the option to have a helper class to hold all my decorators that can be used instead of the only class in which it's defined.我个人更喜欢选择有一个helper class来保存我所有可以使用的decorators ,而不是它定义的唯一 class。 This would give you the flexibility to reuse the decorators instead of redefining them which would follow the ideology这将使您可以灵活地重用装饰器,而不是重新定义它们,这将遵循意识形态

code once, reuse over and over again.一次编码,一遍又一遍地重用。

Your second code example is functionally equivalent to a standard decorator.您的第二个代码示例在功能上等同于标准装饰器。 The standard decorator syntax is just a shorthand for the same thing, namely, reassigning a function value equal to a closure (a function pointer with arguments predefined), where the closure is your decorator wrapper holding the original as its predefined argument.标准装饰器语法只是同一事物的简写,即重新分配等于闭包的 function 值(预定义为 arguments 的 function 指针),其中闭包是您的装饰器包装器,将原始值作为其预定义参数。

Here's an equivalent with standard syntax.这是标准语法的等价物。 Notice you need to create the counter class instance in advance.注意需要提前创建计数器 class 实例。 The decorator syntax refers to that instance, because it must indicate the specific object which holds your counter, rather than just the class of the object:装饰器语法引用该实例,因为它必须指示保存计数器的特定 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