Class method as a decorator
Question:
I have a class where I have multiple methods. I want to use one of the methods as a decorator for other methods. For this I am using following syntax:
@self.action
def execute(self,req):
where action is other method in my class. But it doesn’t work and throws exception as
name 'self' is not defined
Answers:
You cannot use a method of the class while defining it; there is no self
within the class nor is the class ‘baked’ yet to even access any class.
You can treat methods as functions to use as a decorator:
class SomeClass():
def action(func):
# decorate
return wrapper
@action
def execute(self, req):
# something
If action
is defined on a base class, then you’d have to refer to the name via the base class:
class Base():
@staticmethod
def action(func):
# decorate
return wrapper
class Derived(Base):
@Base.action
def execute(self, req):
# something
For Python 2, you’d have to make action
a static method here, as otherwise you get an unbound method that’ll complain you cannot call it without an instance as the first argument. In Python 3, you can leave off the @staticmethod
decorator there, at least for the purposes of the decorator.
But note that action
cannot then be used as a method directly; perhaps it should not be part of the class at all at that point. It is not part of the end-user API here, presumably the decorator is not used by consumers of the instances of these classes.
In python “self” is passed to instance methods as an argument (the first), “self” is just a convention is possible to call it “foobarbaz” (of course it would be silly)… the point is that, from the outside “self” is not defined (because its scope is the method)… you can’t decorate class methods with other class methods, instead you have to write a separate class!
Just beware that both the decorator and the decorated function are unbound methods, so you can only access the self (or cls for classmethods) in the inner scope of the decorator, and must manually bind the decorated method to the instance bound in the inner decorator.
class A:
x = 5
y = 6
def decorate(unbound):
def _decorator(self):
bound = unbound.__get__(self)
return bound(self) * self.x
return _decorator
@decorate
def func(self):
return self.y
A().func() # 30!!
Still trying to wrap my head around how decorators could be inherited and overridden.
I have a class where I have multiple methods. I want to use one of the methods as a decorator for other methods. For this I am using following syntax:
@self.action
def execute(self,req):
where action is other method in my class. But it doesn’t work and throws exception as
name 'self' is not defined
You cannot use a method of the class while defining it; there is no self
within the class nor is the class ‘baked’ yet to even access any class.
You can treat methods as functions to use as a decorator:
class SomeClass():
def action(func):
# decorate
return wrapper
@action
def execute(self, req):
# something
If action
is defined on a base class, then you’d have to refer to the name via the base class:
class Base():
@staticmethod
def action(func):
# decorate
return wrapper
class Derived(Base):
@Base.action
def execute(self, req):
# something
For Python 2, you’d have to make action
a static method here, as otherwise you get an unbound method that’ll complain you cannot call it without an instance as the first argument. In Python 3, you can leave off the @staticmethod
decorator there, at least for the purposes of the decorator.
But note that action
cannot then be used as a method directly; perhaps it should not be part of the class at all at that point. It is not part of the end-user API here, presumably the decorator is not used by consumers of the instances of these classes.
In python “self” is passed to instance methods as an argument (the first), “self” is just a convention is possible to call it “foobarbaz” (of course it would be silly)… the point is that, from the outside “self” is not defined (because its scope is the method)… you can’t decorate class methods with other class methods, instead you have to write a separate class!
Just beware that both the decorator and the decorated function are unbound methods, so you can only access the self (or cls for classmethods) in the inner scope of the decorator, and must manually bind the decorated method to the instance bound in the inner decorator.
class A:
x = 5
y = 6
def decorate(unbound):
def _decorator(self):
bound = unbound.__get__(self)
return bound(self) * self.x
return _decorator
@decorate
def func(self):
return self.y
A().func() # 30!!
Still trying to wrap my head around how decorators could be inherited and overridden.