[ACCEPTED]-How can I use a class instance variable as an argument for a method decorator in Python?-decorator
It's not going to work; the decorator is 8 called during class creation time, which is long before 7 an instance is created (if that ever happens). So 6 if your "decorator" needs the instance, you 5 have to do the "decorating" at instantiation 4 time:
def get_decorator(arg1): def my_decorator(function): print "get_decorator argument: %s" % arg1 return function return my_decorator class Foo(object): def __init__(self, arg1): self.var1 = arg1 self.method1 = get_decorator(self.var1)(self.method1) def method1(self): print "method1" foo = Foo("abc") foo.method1()
Note that I changed the function names 3 according to their meanings; the actual 2 "decorator", i.e. the function that (potentially) modifies 1 the method, is
wrapper in your case, not
Your “warper” function is actually a decorator, rather 6 than a warper. Your “decorator1” function 5 is a decorator constructor. If you want 4 to have access to self.var1 in runtime you 3 have to make a warper not decorator:
def decorator(function): def wrapper(self,*args,**kwargs): print "Doing something with self.var1==%s" % self.var1 return function(self,*args,**kwargs) return wrapper class Foo(object): def __init__(self, arg1): self.var1 = arg1 @decorator def method1(self): print "method1" foo = Foo("abc") foo.method1()
If 2 you want to have more generic decorator, it's 1 better idea to declare a callable class:
class decorator: def __init__(self,varname): self.varname = varname def __call__(self,function): varname=self.varname def wrapper(self,*args,**kwargs): print "Doing something with self.%s==%s" % (varname,getattr(self,varname)) return function(self,*args,**kwargs) return wrapper
Here's how we used to do this in the olden 5 days.
class Foo(object): def __init__(self, arg1): self.var1 = arg1 def method1(self): self.lock() try: self.do_method1() except Exception: pass # Might want to log this finally: self.unlock() def do_method1(self): print "method1" def lock(self): print "locking: %s" % self.arg1 def unlock(self): print "unlocking: %s" % self.arg1
Now, a subclass only needs to o override 4
do_method1 to get the benefits of the "wrapping". Done 3 the old way, without any
Yes, it's 2 long-winded. However, it doesn't involve 1 any magic, either.
Do not try to juggle with decorators for 16 this problem, it is going to make your code 15 very complex and unpleasant to read.
You 14 are attempting to construct a wrapper at 13 class creation time with information that 12 is only going to be available from instantiation 11 time on. You can build the decorator dynamically 10 at instantiation time, but still the outer 9 class level at which you will need to apply 8 the decorator to the methods will not have 7 access to instance variables.
For avoiding 6 the mess that implies to solve this problem 5 with decorators, Python incorporates (from 4 2.7 on) a dedicated data model for solving 3 this specific type of problem. It is called 2
context manager and you can implement it by just using 1 a generator.
from contextlib import contextmanager def lock_file(file): print('File %s locked' % file) def unlock_file(file): print('File %s unlocked' % file) @contextmanager def file_locked(arg1): lock_file(arg1) yield unlock_file(arg1) class Foo(object): def __init__(self, arg1): self.var1 = arg1 def method1(self): with file_locked(self.var1) as f: print "method1" foo = Foo("abc") foo.method1()
The decorator is executed when the class 2 is defined, so you can't pass an instance 1 variable to it.
Nested Methods made the trick, I was having 3 a problem to passing self again while using 2 it. Later I wrapped the function assignment 1 with lambda to resolve the issue.
More Related questions