简体   繁体   English

如何在类中使用装饰器

[英]how to use decorator in a class

I know there is similar question, but my scenario is somehow different: refer to codes: 我知道有类似的问题,但我的情况有些不同:参考代码:

class MyClass(object):
    def __init__(self, log_location)
        self.logs = logging(log_location) # create log object by the log_location, this object should be used by the decorator fucntion

    def record_log(log_object): 
        """ this is the decorator function
        """
        def deco(func):
            def wrap(*args, **kwargs):
                rs = func()

                # use log object to record log
                if rs:
                    log_object.record('success')
                else:
                    log_object.record('fail')

            return wrap
        return deco

   @record_log(self.logs) 
   def test(self):
       rs = do_some_thing
       if rs:
            return True
       return False

def main():
    my_class = MyClass()
    my_class.test()   

But, there is an error like this: 但是,有这样的错误:

@record_log(self.logs)
NameError: name 'self' is not defined

Hos should I use the instance attribute self.logs in a decorator function in such scenario like this?? 我应该在这样的场景中使用装饰器函数中的实例属性self.logs吗?

Thanks very much! 非常感谢!

You can not pass a reference to self or any attribute of self at this point. 此时您无法传递对self或任何self属性的引用。 The @record_log line is executed (the method is decorated) before the code in main is executed, ie before any instance of MyClass is created at all -- in fact, even before the definition of MyClass has been completed! 在执行main代码之前,即在创建任何MyClass实例之前执行@record_log行(方法被修饰) - 事实上,甚至在MyClass的定义完成之前! But remember that 但请记住

@record_log(self.logs) 
def test(self, n):

is actually just syntactic sugar for 实际上只是语法糖

test = record_log(self.logs)(test)

So one way to work around your problem would be to redefine test in your __init__ , ie 因此解决问题的一种方法是在__init__重新定义test ,即

def __init__(self, log_location)
    self.logs = logging(log_location)
    self.test = record_log(self.logs)(self.test)

Also note that your decorator is not passing any parameters to func and not returning the results. 另请注意,您的装饰器未将任何参数传递给func而不返回结果。 Also, it should probably be defined on module level (before the class). 此外,它应该在模块级别(在课前)定义。

def record_log(log_object): 
    def deco(func):
        def wrap(*args, **kwargs):
            rs = func(*args, **kwargs)   # pass parameters
            if rs:
                log_object.record('success')
            else:
                log_object.record('fail')
            return rs   # return result
        return wrap
    return deco

There are several objections about your code: 您的代码有几个异议:

  1. deco() is redundant. deco()是多余的。 You can directly return wrap from record_log() . 您可以直接从record_log()返回wrap record_log()

  2. If you only plan to decorate MyClass 's methods, then there is no point in passing log_object to the decorator, as self.logs will always be used. 如果您只打算装饰MyClass的方法,那么将log_object传递给装饰器是没有意义的,因为将始终使用self.logs Otherwise, consider moving the decorator to module level, as already suggested by others. 否则,考虑将装饰器移动到模块级别,如其他人已经建议的那样。

  3. The decorated method's return value is currently lost. 装饰方法的返回值当前丢失。

  4. The call to the decorated function does not pass self to it. 对装饰函数的调用不会将self传递给它。

The proper code would therefore be: 因此,正确的代码是:

class MyClass(object):
    def __init__(self, log_location):
        self.logs = logging(log_location)

    def record_log(func):
        """ this is the decorator function
        """
        def wrap(self):
            rs = func(self)
            # use log object to record log
            if rs:
                print 1
                self.logs.record('success')
            else:
                print 2
                self.logs.record('fail')
            return rs
        return wrap

    @record_log
    def test(self):
       rs = do_some_thing
       if rs:
            return True
       return False

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM