Inside the decorator class, an access instance of the class that contains the decorated method

I have the following decorator that saves the configuration file after calling the method decorated with @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" 

I use this decorator inside the next class. After calling the createkvm method, the createkvm configuration self.cfg must 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 self.cfg object self.cfg inside the saveconfig decorator. The first naive approach was to add a parameter to the decorator that holds the object, for example @saveconfig(self) , but this does not work.

How can I access the variables of a method host object inside a decorator? Do I have to define a decorator inside the same class in order to access?

+8
python decorator
source share
3 answers

To be able to access the instance, you must make your descriptor decorator class

 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 the first parameter to self.f() , where it should pass an instance of pbtools .

+11
source share

You pass object as self to the decorated method. The point is, you cannot easily get self , because Python sees the decorated method, which is now an object, and does not consider it a method (which should be passed to self when called - or, more generally, that should work as a property returning the associated method). You can get around this as @Sven Marnach noted.

However, you can easily rewrite this decorator without a class using closure (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 component: there is no class variable in the example. The class variable would be x = ... indented before the method definition and should be shared between all instances (in particular, it would be an attribute of the pbtools object) - everything on self is an instance attribute.
  • During class definition (when you define methods, apply decorators, etc.) there is no self !
+4
source share

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 should be a class, then you need a Sven solution.

0
source share

All Articles