I am new to Python decorators (wow, great feature!), and I have trouble getting the following to work because the self
argument gets sort of mixed up.
#this is the decorator
class cacher(object):
def __init__(self, f):
self.f = f
self.cache = {}
def __call__(self, *args):
fname = self.f.__name__
if (fname not in self.cache):
self.cache[fname] = self.f(self,*args)
else:
print "using cache"
return self.cache[fname]
class Session(p.Session):
def __init__(self, user, passw):
self.pl = p.Session(user, passw)
@cacher
def get_something(self):
print "get_something called with self = %s "% self
return self.pl.get_something()
s = Session(u,p)
s.get_something()
When I run this, I get:
get_something called with self = <__main__.cacher object at 0x020870F0>
Traceback:
...
AttributeError: 'cacher' object has no attribute 'pl'
for the line where I do self.cache[fname] = self.f(self,*args)
The problem - Obviously, the problem is that self
is the cacher object instead of a Session instance, which indeed doesn't have a pl
attribute. However I can't find how to solve this.
Solutions I've considered, but can't use - I thought of making the decorator class return a function instead of a value (like in section 2.1 of this article) so that self
is evaluated in the right context, but that isn't possible since my decorator is implemented as a class and uses the build-in __call__
method. Then I thought to not use a class for my decorator, so that I don't need the __call__method, but I can't do that because I need to keep state between decorator calls (i.e. for keeping track of what is in the self.cache
attribute).
Question - So, apart from using a global cache
dictionary variable (which I didn't try, but assume will work), is there any other way to make this decorator work?
Edit: this SO question seems similar Decorating python class methods, how do I pass the instance to the decorator?
Session
will share the same cache? – Gothicism