I am working on finding a way to reduce boilerplate decorators. We have a lot of classes that use a @decorate. For example:
class MyClass(Base):
@decorate
def fun1(self):
pass
@decorate
def fun2(self):
pass
def fun3(self):
pass
I want to make it so by default the decorator is there, unless someone specifies otherwise.
I use this code to do the autowrap
from functools import wraps
def myDecorator(func):
@wraps(func)
def decorator(self, *args, **kwargs):
try:
print 'enter'
ret = func(self, *args, **kwargs)
print 'leave'
except:
print 'exception'
ret = None
return ret
return decorator
class TestDecorateAllMeta(type):
def __new__(cls, name, bases, local):
for attr in local:
value = local[attr]
if callable(value):
local[attr] = myDecorator(value)
return type.__new__(cls, name, bases, local)
class TestClass(object):
__metaclass__ = TestDecorateAllMeta
def test_print2(self, val):
print val
def test_print(self, val):
print val
c = TestClass()
c.test_print1("print 1")
c.test_print2("print 2")
My question are:
- Is there a better way to accompish auto-decorating?
- How can I go about overriding?
Ideally my end solution would be something like:
class TestClass(object):
__metaclass__ = TestDecorateAllMeta
def autowrap(self):
print("Auto wrap")
@dont_decorate
def test_dont_decorate(self, val):
print val
Edit
To speak to one of the comments below, since classess are callable instead of doing
if callable(value):
It should read:
if isinstance(value,types.FunctionType)
Rather than making the user of my class specify a
__metaclass__attribute I would just have them derive from my base class that defines it. No need to expose the plumbing unnecessarily.Other than that, looks good, though. Your
@dont_decoratefunction decorator can be implemented by setting an attribute on the original function, which your class decorator then detects and skips the decoration if it is present.Then in your metaclass, where you now have the line
if callable(value):just put:As an aside, classes are callable so if you don’t want inner classes decorated, you should probably check for functions using
isinstance()rather thancallable().If you are interested in more explicit alternatives, you might take a look at this recent question where someone wanted to do essentially the same thing using a class decorator. Unfortunately, this is a good bit more complicated because the methods are already wrapped by the time the decorator sees them.