问题
I have the following decorator, which saves a configuration file after a method decorated with @saveconfig is called:
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"
I'm using this decorator inside the following class. After the method createkvm is called, the configuration object self.cfg should be saved inside the decorator:
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"
My problem is that i need to access the object variable self.cfg inside the decorator saveconfig. A first naive approach was to add a parameter to the decorator which holds the object, like @saveconfig(self), but this doesn't work.
How can I access object variables of the method host inside the decorator? Do i have to define the decorator inside the same class to get access?
回答1:
You have to make your decorator class behave as a descriptor to be able to access the instance:
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
Your code passes object as first parameter to self.f(), where it should pass the pbtools instance.
回答2:
You are passing object as self to the decorated method. The thing is, you can't easily get self because Python sees the decorated method, which is now an objects, and doesn't consider it a method (that should be passed self when called - or, more generally, that should work as a property returning a bound method). You can work around this, as pointed out by @Sven Marnach.
However, you could easily rewrite this decorator without a class, using a closure (is a bit shorter and also solves the above problem):
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
Other notes:
- Terminology mixup: There is no class variable in the example. A class variable would be
x = ...indented as far as the method definitions and be shared between all instances (specifically, it would be an attribute of the object that ispbtools) - everything onselfis an instance attribute. - At class definition time (when you define methods, apply decorators, etc.) there is no
self!
回答3:
You can also use a simple function for what you want:
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
If saveconfig must be a class then you need Sven's solution.
来源:https://stackoverflow.com/questions/4987471/inside-a-decorator-class-access-instance-of-the-class-which-contains-the-decora