如何在类中使用装饰器

时间:2015-04-22 08:59:36

标签: python decorator python-decorators

我知道有类似的问题,但我的情况有所不同:参考代码:

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

但是,有这样的错误:

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

我应该在装饰函数中使用实例属性self.logs,就像这样的场景吗?

非常感谢!

2 个答案:

答案 0 :(得分:1)

此时您无法传递对System.identityHashCode(this)self的任何属性的引用。 self行在执行@record_log中的代码之前执行(方法已修饰),即在创建任何main实例之前 - 实际上,甚至在定义之前MyClass已完成!但请记住

MyClass

实际上只是

的语法糖
@record_log(self.logs) 
def test(self, n):

因此解决问题的一种方法是在test = record_log(self.logs)(test) 中重新定义test,即

__init__

另请注意,您的装饰器未将任何参数传递给def __init__(self, log_location) self.logs = logging(log_location) self.test = record_log(self.logs)(self.test) 并且未返回结果。此外,它应该在模块级别(在课前)定义。

func

答案 1 :(得分:1)

您的代码有几个异议:

  1. deco()是多余的。您可以直接从wrap返回record_log()

  2. 如果您只打算装饰MyClass的方法,那么将log_object传递给装饰器是没有意义的,因为始终会使用self.logs 。否则,请考虑将装饰器移动到模块级别,如其他人已经建议的那样。

  3. 装饰方法的返回值目前已丢失。

  4. 对装饰函数的调用未将self传递给它。

  5. 因此正确的代码是:

    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