[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 decorator1
.
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
Using:
@decorator("var1")
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 with
statement.
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.
https://gist.github.com/kirankotari/e6959e74316352bfd06afa4d5ab8bd52
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.