To decorate a method in a class, first use the '@' symbol followed by the name of the decorator function. A decorator is simply a function that takes a function as an argument and returns yet another function. Here, when we decorate, multiply_together with integer_check, the integer function gets called.
This allows for the existence of higher-order functions (HOFs) that can take and/or return other functions. A decorator is essentially a HOF; it takes an entity (a standalone function, a class function, or even a whole class) and returns a function or a class reference.
In Python, decorators can be either functions or classes. In both cases, decorating adds functionality to existing functions. When we decorate a function with a class, that function becomes an instance of the class.
Decorators can be chained A Decorator function is used only to format the output of another function dec keyword is used for decorating a function Decorators always return None”
Decorate the class with a function that walks through the class's attributes and decorates callables. This may be the wrong thing to do if you have class variables that may happen to be callable, and will also decorate nested classes (credits to Sven Marnach for pointing this out) but generally it's a rather clean and simple solution. Example implementation (note that this will not exclude special methods (__init__
etc.), which may or may not be desired):
def for_all_methods(decorator):
def decorate(cls):
for attr in cls.__dict__: # there's propably a better way to do this
if callable(getattr(cls, attr)):
setattr(cls, attr, decorator(getattr(cls, attr)))
return cls
return decorate
Use like this:
@for_all_methods(mydecorator)
class C(object):
def m1(self): pass
def m2(self, x): pass
...
In Python 3.0 and 3.1, callable
does not exist. It existed since forever in Python 2.x and is back in Python 3.2 as wrapper for isinstance(x, collections.Callable)
, so you can use that (or define your own callable
replacement using this) in those versions.
While I'm not fond of using magical approaches when an explicit approach would do, you can probably use a metaclass for this.
def myDecorator(fn):
fn.foo = 'bar'
return fn
class myMetaClass(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 myClass(object):
__metaclass__ = myMetaClass
def baz(self):
print self.baz.foo
and it works as though each callable in myClass
had been decorated with myDecorator
>>> quux = myClass()
>>> quux.baz()
bar
Not to revive things from the dead, but I really liked delnan's answer, but found it sllliigghhtttlllyy lacking.
def for_all_methods(exclude, decorator):
def decorate(cls):
for attr in cls.__dict__:
if callable(getattr(cls, attr)) and attr not in exclude:
setattr(cls, attr, decorator(getattr(cls, attr)))
return cls
return decorate
EDIT: fix indenting
So you can specify methods//attributes//stuff you don't want decorated
None of the above answers worked for me, since I wanted to also decorate the inherited methods, which was not accomplished by using __dict__
, and I did not want to overcomplicate things with metaclasses. Lastly, I am fine with having a solution for Python 2, since I just have an immediate need to add some profiling code for measuring time used by all functions of a class.
import inspect
def for_all_methods(decorator):
def decorate(cls):
for name, fn in inspect.getmembers(cls, inspect.ismethod):
setattr(cls, name, decorator(fn))
return cls
return decorate
Source (slightly different solution): https://stackoverflow.com/a/3467879/1243926 There you can also see how to change it for Python 3.
As comments to other answers suggest, consider using inspect.getmembers(cls, inspect.isroutine)
instead. If you have found a proper solution that works for both Python 2 and Python 3 and decorates inherited methods, and can still be done in 7 lines, please, edit.
You could generate a metaclass. This will not decorate inherited methods.
def decorating_meta(decorator):
class DecoratingMetaclass(type):
def __new__(self, class_name, bases, namespace):
for key, value in list(namespace.items()):
if callable(value):
namespace[key] = decorator(value)
return type.__new__(self, class_name, bases, namespace)
return DecoratingMetaclass
This will generate a metaclass decorating all methods with the specified function. You can use it in Python 2 or 3 by doing something like this
def doubling_decorator(f):
def decorated(*a, **kw):
return f(*a, **kw) * 2
return decorated
class Foo(dict):
__metaclass__ = decorating_meta(doubling_decorator)
def lookup(self, key):
return self[key]
d = Foo()
d["bar"] = 5
print(d.lookup("bar")) # prints 10
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With