voodoo: modifying class methods a posteriori

Paul Winkler slinkp23 at yahoo.com
Wed Sep 19 07:49:13 CEST 2001


On Tue, 18 Sep 2001 18:00:32 -0000, hungjunglu at yahoo.com wrote:
(snip)
>Now, all that is nice. BUT, usually, when you override a method, you 
>probably want to do just a bit more than what the old method was 
>doing.
(snip)
>Is there a way of doing the same thing without subclassing?

This is exactly what the Decorator design pattern is for.  Note: I
only just learned about Decorators today, so don't take this as gospel
- I may have misunderstood something. But the following seems to work,
it satisfies the criteria of the Decorator as I understand it, and it
does exactly what you're asking for:

class Decorator:
    """An abstract Decorator class based on one posted to comp.lang.python
    by Rainer Deyke.
    """
    def __init__(self, decorated):
        self._decorated = decorated
    def __getattr__(self, name):
        return getattr(self._decorated, name)
    def __call__(self, *args, **kwargs):
        self._decorated(*args, **kwargs)
    # Override other operators too.

class MyDecorator(Decorator):
    def f(self):
        print "before saying something"
        self._decorated.f()
        print "after saying something"

class A:
    def __init__(self):
        self.foo = "I am an attribute of A."
    def f(self):
        print 'Hello from A.f()'

# Now let's test it.
a = MyDecorator(A())
# Note that a now behaves identically to an instance of A in
# all respects, except that we've "decorated" one method.

a.f()
print a.foo

# end script

Here's the output that produces:

before saying something
Hello from A.f()
after saying something
I am an attribute of A.


Note a couple of things that make this really cool:

1) you can use any number of decorators chained together in any
combination, e.g.

a = Decorator1(Decorator2(Decorator3(A())))

Since you'll get different results depending on what order you put the
decorators in, defining 3 decorators gives you ... uh... 15 unique
combinations of 1 to 3 decorators. Compare that to making 15
subclasses of A to get the same flexibility.

2) you can use the same decorators for any number of different objects
as long as they provide the method(s) you're decorating.


--PW



More information about the Python-list mailing list