29

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?

asked Jun 25, 2010 at 14:45
4
  • 1
    Can you give a example where simply subclassing wouldnt work? You can subclass dynamically too - this pattern seems like a workaround for languages that can't do that or don't support multiple inheritage. Commented Jun 25, 2010 at 15:26
  • 1
    I want to decorate objects at runtime. I want to apply different decorators to an object and be able to remove them again. Subclassing cannot change an instance after it has been created, or can it? Commented Jun 25, 2010 at 15:50
  • If you have class A and change A, ie adding a new method, A.foo = lambda self: self this will reflect on all instances of A .. because everything is determined at runtime. Great way to produce absolutely unmaintainable code. Commented Jun 25, 2010 at 17:01
  • 7
    @THC4K: The decorator pattern (as opposed to python decorators) is used to add behavior to an object at runtime. This is actually very maintainable, when done correctly, which is why I posted this question. I wanted to find the way to this in Python. Commented Jun 26, 2010 at 11:13

7 Answers 7

34

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()
answered Jun 25, 2010 at 15:00
4
  • 2
    This is a great idea. It should be noted, however, that if you use Abstract Base Classes (ie import abc and use metaclass = abc.ABCMeta to define abstract methods and properties) then it will not work. Commented Feb 23, 2012 at 18:28
  • This doesn't work for functions like str. What is happening there? Commented May 2, 2016 at 15:22
  • @JohnKitchin: The redirection doesn't work for double underscore methods, because these must (for performance reasons) be defined on the class, not the instance. (more info) I believe the only workaround is to explicitly define and redirect methods like __str__. Commented Sep 5, 2016 at 9:28
  • 1
    Is this really the "accepted" way of setting up the decorator pattern? Overwriting a "double underscore" method feels hacky. Commented Sep 4, 2018 at 20:31
11

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()
answered Jul 30, 2010 at 13:19
1
  • This seems to execute the decoratee's __init__() again, passing it decoratee, which is probably not desired. Commented Feb 7, 2019 at 12:15
2

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)
answered Jun 25, 2010 at 14:53
3
  • 1
    I considered this as well, but it feels very wrong to me. Maybe that is because I come from C++? Commented Jun 25, 2010 at 14:56
  • 2
    It's fair to feel wrong about it. It could be considered monkey patching. However it works well with little code, it's a very different world with more possibilities from C when everything is dynamic & by reference. Commented Jun 25, 2010 at 15:16
  • I like it. For this example, anything else would just introduce more complexity IMO. Commented Mar 6, 2015 at 2:03
2

The UML diagram in the linked Wikipedia article is wrong and so is your code.

If you follow the "decorator pattern", the decorator class is derived from the base decorated class. (In the UML diagram an inheritance arrow from the WindowDecorator to Window is missing).

with

class foo_decorator(foo):

you don't need to implement undecorated methods.

BTW: In strong typed languages there is one more reason, why the decorator must be derived from the decorated class: Otherwise you wouldnt be able to chain decorators.

answered Jul 30, 2010 at 12:36
1
  • The UML diagram shows both inheritance and aggregation (two essential parts for decorator pattern) of the base class. You inherit from the base class, so you look like the original, and you hold a reference to an instance of the base class where you can insulate access to it. The wikipedia article says this in steps 1 and 2: "(1) Subclass the original Component, (2) add a Component pointer as a field". So the original question is actually about Python duck typing, and neither about the decorator patter, nor Python decorators! Commented Dec 26, 2014 at 19:51
1

In one of my projects, I also needed to do one particular thing, that is that even the underlying object should actually execute the method that was reimplemented in the decorator. It is actually quite easy to do if you know where to target it.

The use case is:

  • I have an object X with methods A and B.
  • I create a decorator class Y that overrides A.
  • If I instantiate Y(X) and call A, it will use the decorated A as expected.
  • If B calls A, then if I instantiate Y(X) and call B on the decorator, the call from within B then goes to the old A on the original object which was undesirable. I want the old B to call the new A as well.

It is possible to reach this behaviour like this:

import inspect
import six # for handling 2-3 compatibility
class MyBaseDecorator(object):
 def __init__(self, decorated):
 self.decorated = decorated
 def __getattr__(self, attr):
 value = getattr(self.decorated, attr)
 if inspect.ismethod(value):
 function = six.get_method_function(value)
 value = function.__get__(self, type(self))
 return value
class SomeObject(object):
 def a(self):
 pass
 def b(self):
 pass
class MyDecorator(MyBaseDecorator):
 def a(self):
 pass
decorated = MyDecorator(SomeObject())

This may not work out of the box as I typed everything else apart from the getattr method from top of my head.

The code looks up the requested attribute in the decorated object, and if it is a method (doesn't work for properties now, but the change to support them should not be too difficult), the code then pulls the actual function out of the method and using the descriptor interface invocation it "rebinds" the function as a method, but on the decorator. Then it is returned and most likely executed.

The effect of this is that if b ever calls a on the original object, then when you have the object decorated and there is any method call coming from the decorator, the decorator makes sure that all methods accessed are bound to the decorator instead, therefore looking up things using the decorator and not the original object, therefore the methods specified in the decorator taking precedence.

P.S.: Yes I know it looks pretty much like inheritance, but this done in the sense of composition of multiple objects.

answered Dec 6, 2017 at 15:38
0

To complement @Alec Thomas reply. I modified his answer to follow the decorator pattern. This way you don't need to know the class you're decorating in advance.

class Decorator(object):
 def __new__(cls, decoratee):
 cls = type('decorated',
 (cls, decoratee.__class__),
 decoratee.__dict__)
 return object.__new__(cls)

Then, you can use it as:

class SpecificDecorator(Decorator):
 def f1(self):
 print "decorated f1"
 super(foo_decorator, self).f1()
class Decorated(object):
 def f1(self):
 print "original f1"
d = SpecificDecorator(Decorated())
d.f1()
answered Mar 28, 2015 at 9:43
0

In Python 3, Philipp's accepted answer raised RuntimeError: maximum recursion depth exceeded.

The way that worked for me:

class Foo(object):
 def f1(self):
 print("original f1")
 def f2(self):
 print("original f2")
class FooDecorator(object):
 def __init__(self, decoratee):
 self._decoratee = decoratee
 def f1(self):
 print("decorated f1")
 return self._decoratee.f1()
 def __getattr__(self, name):
 if name in ['f1', '_decoratee']:
 raise AttributeError()
 return getattr(self._decoratee, name)
f = FooDecorator(Foo())
f.f1()
# decorated f1
# original f1
f.f2()
# original f2

The workaround is inspired by Ned Batchelder's blog

answered Dec 19, 2019 at 15:38

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.