[英]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: 您的代码有几个异议:
deco()
is redundant. deco()
是多余的。 You can directly return wrap
from record_log()
. 您可以直接从
record_log()
返回wrap
record_log()
。
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. 否则,考虑将装饰器移动到模块级别,如其他人已经建议的那样。
The decorated method's return value is currently lost. 装饰方法的返回值当前丢失。
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.