Create a decorator that can see the current class method

Can you create a decorator inside a class that will see class methods and variables?

The decorator does not see here: self.longcondition ()

class Foo: def __init__(self, name): self.name = name # decorator that will see the self.longcondition ??? class canRun(object): def __init__(self, f): self.f = f def __call__(self, *args): if self.longcondition(): # <-------- ??? self.f(*args) # this is supposed to be a very long condition :) def longcondition(self): return isinstance(self.name, str) @canRun # <------ def run(self, times): for i in xrange(times): print "%s. run... %s" % (i, self.name) 
+4
source share
3 answers

You may have a class, but you need to use the descriptor protocol

  import types class canRun(object): def __init__(self, f): self.f = f self.o = object # <-- What the hell is this about? def __call__(self, *args): if self.longcondition(): self.f(*args) def __get__(self, instance, owner): return types.MethodType(self, instance) 

You always need to use a descriptor if you want to decorate class methods with an instance of the class using the __call__ method. The reason for this is that only one self will be passed, which refers to an instance of the decoration class, and not to an instance of the decorated method.

+1
source

There is no real need to implement this decorator as a class, and there is no need to implement it in the definition of the Foo class. The following is enough:

 def canRun(meth): def decorated_meth(self, *args, **kwargs): if self.longcondition(): print 'Can run' return meth(self, *args, **kwargs) else: print 'Cannot run' return None return decorated_meth 

Using this decorator works:

 >>> Foo('hello').run(5) Can run 0. run... hello 1. run... hello 2. run... hello 3. run... hello 4. run... hello >>> Foo(123).run(5) Cannot run 
+5
source

My previous answer was in a hurry. If you want to write a decorator, you really should use wraps from the functools module. He takes care of difficult things for you.

The correct way to define a canRun decorator is:

 from functools import wraps def canRun(f): @wraps(f) def wrapper(instance, *args): if instance.longcondition(): return f(instance, *args) return wrapper 

The canRun function must be defined outside the class.

+1
source

All Articles