I want to implement the decorator pattern in Python, and I wondered if there is a way to write a decorator that just implements the function it wants to modify, without writing boiler-plate for all the functions that are just forwarded to the decorated object. Like so:
class foo(object):
def f1(self):
print "original f1"
def f2(self):
print "original f2"
class foo_decorator(object):
def __init__(self, decoratee):
self._decoratee = decoratee
def f1(self):
print "decorated f1"
self._decoratee.f1()
def f2(self): # I would like to leave that part out
self._decoratee.f2()
I would like to have calls to foo_decorator.f2
forwarded to decoratee.f2
automatically. Is there a way to write a generic method that forwards all unimplemented function-calls to decoratee
?
The decorator pattern can be used to extend (decorate) the functionality of a certain object at run-time, independently of other instances of the same class, provided some groundwork is done at design time. Decorators in Python - Despite the name, Python decorators are not an implementation of the decorator pattern.
The decorator pattern is a software design pattern that allows us to dynamically add functionality to classes without creating subclasses and affecting the behavior of other objects of the same class.
A decorator is a design pattern in Python that allows a user to add new functionality to an existing object without modifying its structure. Decorators are usually called before the definition of a function you want to decorate.
You could use __getattr__
:
class foo(object):
def f1(self):
print "original f1"
def f2(self):
print "original f2"
class foo_decorator(object):
def __init__(self, decoratee):
self._decoratee = decoratee
def f1(self):
print "decorated f1"
self._decoratee.f1()
def __getattr__(self, name):
return getattr(self._decoratee, name)
u = foo()
v = foo_decorator(u)
v.f1()
v.f2()
As an addendum to Philipp's answer; if you need to not only decorate, but preserve the type of an object, Python allows you to subclass an instance at runtime:
class foo(object):
def f1(self):
print "original f1"
def f2(self):
print "original f2"
class foo_decorator(object):
def __new__(cls, decoratee):
cls = type('decorated',
(foo_decorator, decoratee.__class__),
decoratee.__dict__)
return object.__new__(cls)
def f1(self):
print "decorated f1"
super(foo_decorator, self).f1()
u = foo()
v = foo_decorator(u)
v.f1()
v.f2()
print 'isinstance(v, foo) ==', isinstance(v, foo)
This is a bit more involved than strictly necessary for your example, where you know the class being decorated in advance.
This might suffice:
class foo_decorator(foo):
def __init__(self, decoratee):
self.__dict__.update(decoratee.__dict__)
def f1(self):
print "decorated f1"
super(foo_decorator, self).f1()
It's arguably not the best practice, but you can add functionality to instances, as I've done to help transition my code from Django's ORM to SQLAlachemy, as follows:
def _save(self):
session.add(self)
session.commit()
setattr(Base,'save',_save)
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