I don't really need to do this, but was just wondering, is there a way to bind a decorator to all functions within a class generically, rather than explicitly stating it for every function.
I suppose it then becomes a kind of aspect, rather than a decorator and it does feel a bit odd, but was thinking for something like timing or auth it'd be pretty neat.
You could override the
__getattr__
method. It's not actually attaching a decorator, but it lets you return a decorated method. You'd probably want to do something like this:There's some ugly recursion hiding in there that you'll want to protect against, but that's a start.
The cleanest way to do this, or to do other modifications to a class definition, is to define a metaclass.
Alternatively, just apply your decorator at the end of the class definition:
For Python 3 replace types.UnboundMethodType with types.FunctionType.
In practice of course you'll want to apply your decorator more selectively, and as soon as you want to decorate all but one method you'll discover that it is easier and more flexible just to use the decorator syntax in the traditional way.
Of course that the metaclasses are the most pythonic way to go when you want to modify the way that python creates the objects. Which can be done by overriding the
__new__
method of your class. But there are some points around this problem (specially for python 3.X) that I'd like to mention:types.FunctionType
doesn't protect the special methods from being decorated, as they are function types. As a more general way you can just decorate the objects which their names are not started with double underscore (__
). One other benefit of this method is that it also covers those objects that exist in namespace and starts with__
but are not function like__qualname__
,__module__
, etc.The
namespace
argument in__new__
's header doesn't contain class attributes within the__init__
. The reason is that the__new__
executes before the__init__
(initializing).It's not necessary to use a
classmethod
as the decorator, as in most of the times you import your decorator from another module.__init__
) for refusing of being decorated alongside checking if the name is not started with__
you can check the type withtypes.FunctionType
to be sure that you're not decorating a non-function object.Here is a sample metacalss that you can use:
Demo:
Output:
For checking the 3rd item from the aforementioned notes you can uncomment the line
a = 10
and doprint(myinstance.a)
and see the result then change the dictionary comprehension in__new__
as follows then see the result again:Everytime you think of changing class definition, you can either use the class decorator or metaclass. e.g. using metaclass
Output:
Note: it will not decorate staticmethod and classmethod