以下是我的测试代码,它有一个可以改变self(当前对象实例)的类方法的装饰器
class Test(object):
def __init__(self):
self.x = 5
def _change_x(self):
print "in _change_x"
def decorator(f):
print "in decorator"
def wrapped(*args, **kwargs):
print "in wrapped"
print args, kwargs
self.x = 8
f(*args, **kwargs)
return wrapped
return decorator
@_change_x
def print_x(self):
print "in print_x, x: %d" % self.x
return self.x
if __name__ == "__main__":
test = Test()
print "Initial value for x: %d" % test.x
print "Test if it changed? x: %d" % test.print_x()
没有调用包装在装饰器中的内部方法。任何人都可以帮我指出我的测试代码中的错误。 我希望在类中定义这种装饰器,并用于装饰该类中的几个方法以在调用时更改类成员。
答案 0 :(得分:3)
首先,让我们考虑为什么你的代码没有工作......
在调用_change_x
时,该类仍在构建中,因此不能成为该类的任何实例。因此,您的self
参数具有误导性。调用它时,self
实际上是函数print_x
。显然,向self
添加内容不会更改Test
的实例,因为self
不是Test
的实例:-)。 换句话说,在类中定义装饰器函数没有什么特别之处。它唯一能做的就是它还可以在命名空间中添加一个函数_change_x
。次。
我们如何让这个工作呢?嗯,答案是要意识到_change_x
只是装饰方法。在这种情况下,包装器函数的第一个参数将是self
(就像在普通方法中一样),所以我们可以将它放在那里并在wrapped
内使用它:这有效:< / p>
class Test(object):
def __init__(self):
self.x = 5
def _change_x(f):
print "in _change_x"
def wrapped(self, *args, **kwargs):
print "in wrapped"
print args, kwargs
self.x = 8
return f(self, *args, **kwargs)
return wrapped
@_change_x
def print_x(self):
print "in print_x, x: %d" % self.x
return self.x
if __name__ == "__main__":
test = Test()
print "Initial value for x: %d" % test.x
print "Test if it changed? x: %d" % test.print_x()
但事实证明,你根本不需要在课堂上定义装饰器。毕竟,正如我之前所说的那样 - 把它放在课堂上没什么特别的......:
def _change_x(f):
print "in _change_x"
def wrapped(self, *args, **kwargs):
print "in wrapped"
print args, kwargs
self.x = 8
return f(self, *args, **kwargs)
return wrapped
class Test(object):
def __init__(self):
self.x = 5
@_change_x
def print_x(self):
print "in print_x, x: %d" % self.x
return self.x
if __name__ == "__main__":
test = Test()
print "Initial value for x: %d" % test.x
print "Test if it changed? x: %d" % test.print_x()
答案 1 :(得分:0)
问题是_change_x是装饰器本身,包装器需要将self作为参数:
def _change_x(f):
print "in _change_x decorator"
def wrapped(self,*args, **kwargs):
print "in wrapped"
print args, kwargs
self.x = 8
f(self,*args, **kwargs)
#maybe return f(*args,**kw)?
return wrapped
这可能会令人困惑,因为作为装饰器,它不是实例上的方法,因此您可能要么在使用它之后将其从类范围中删除,要么在类外定义它范围(仍然以同样的方式)
编辑:如果您在类中定义了_change_x
,那么在类定义的底部添加_change_x = staticmethod(_change_x)
,您仍然可以在类定义之后将该函数作为staticmethod使用,尽管您不能这样做直到你在相同的范围内完成它。 (除非你做了@_change_x.__get__(0)
这是非常不必要的)