我有以下装饰器,它在调用用@saveconfig
修饰的方法后保存配置文件:
class saveconfig(object):
def __init__(self, f):
self.f = f
def __call__(self, *args):
self.f(object, *args)
# Here i want to access "cfg" defined in pbtools
print "Saving configuration"
我在下面的类中使用这个装饰器。在调用方法createkvm
之后,配置对象self.cfg
应该保存在装饰器中:
class pbtools()
def __init__(self):
self.configfile = open("pbt.properties", 'r+')
# This variable should be available inside my decorator
self.cfg = ConfigObj(infile = self.configfile)
@saveconfig
def createkvm(self):
print "creating kvm"
我的问题是我需要访问装饰器self.cfg
内的对象变量saveconfig
。第一个天真的方法是向装饰器添加一个参数来保存对象,如@saveconfig(self)
,但这不起作用。
如何在装饰器中访问方法主机的对象变量?我是否必须在同一个类中定义装饰器才能获得访问权限?
答案 0 :(得分:11)
您必须使您的装饰器类表现为descriptor才能访问该实例:
class saveconfig(object):
def __init__(self, f):
self.f = f
def __get__(self, instance, owner):
def wrapper(*args):
print "Saving configuration"
print instance.cfg
return self.f(instance, *args)
return wrapper
您的代码将object
作为第一个参数传递给self.f()
,应传递pbtools
个实例。
答案 1 :(得分:4)
您正在将object
作为self
传递给已修饰的方法。问题是,你不能轻易得到self
因为Python看到了装饰方法,它现在是一个对象,并且不认为它是一个方法(在调用时应该传递self
- 或者更一般地说,它应该作为返回绑定方法的属性工作)。正如@Sven Marnach所指出的那样,你可以解决这个问题。
但是,您可以轻松地在没有类的情况下重写此装饰器,使用闭包(稍微缩短并解决上述问题):
def saveconfig(f):
@functools.wraps(f) # to preserve name, docstring, etc.
def wrapper(*args, **kwargs): # **kwargs for compability with functions that use them
f(*args, **kwargs)
# save config
return wrapper
其他说明:
x = ...
缩进到方法定义,并在所有实例之间共享(具体来说,它将是对象的属性pbtools
) - self
上的所有内容是一个实例属性。self
!答案 2 :(得分:0)
您也可以根据需要使用简单的功能:
def saveconfig(f):
# this method replaces the decorated, so `self` will be the pbtools instance
def wrapped(self, *args):
f(self, *args)
# Here i want to access "cfg" defined in pbtools
print "Saving configuration", self.cfg
return wrapped
如果saveconfig
必须是一个班级,那么你需要Sven的解决方案。