Removing inheritance (decorator pattern ?)

George Sakkis george.sakkis at gmail.com
Mon Jun 16 10:55:54 EDT 2008


On Jun 16, 5:04 am, "Diez B. Roggisch" <de... at nospam.web.de> wrote:

> Diez B. Roggisch wrote:
> > George Sakkis schrieb:
> >> I have a situation where one class can be customized with several
> >> orthogonal options. Currently this is implemented with (multiple)
> >> inheritance but this leads to combinatorial explosion of subclasses as
> >> more orthogonal features are added. Naturally, the decorator pattern
> >> [1] comes to mind (not to be confused with the the Python meaning of
> >> the term "decorator").
>
> >> However, there is a twist. In the standard decorator pattern, the
> >> decorator accepts the object to be decorated and adds extra
> >> functionality or modifies the object's behavior by overriding one or
> >> more methods. It does not affect how the object is created, it takes
> >> it as is. My multiple inheritance classes though play a double role:
> >> not only they override one or more regular methods, but they may
> >> override __init__ as well. Here's a toy example:
>
> >> class Joinable(object):
> >>     def __init__(self, words):
> >>         self.__words = list(words)
> >>     def join(self, delim=','):
> >>         return delim.join(self.__words)
>
> >> class Sorted(Joinable):
> >>     def __init__(self, words):
> >>         super(Sorted,self).__init__(sorted(words))
> >>     def join(self, delim=','):
> >>         return '[Sorted] %s' % super(Sorted,self).join(delim)
>
> >> class Reversed(Joinable):
> >>     def __init__(self, words):
> >>         super(Reversed,self).__init__(reversed(words))
> >>     def join(self, delim=','):
> >>         return '[Reversed] %s' % super(Reversed,self).join(delim)
>
> >> class SortedReversed(Sorted, Reversed):
> >>     pass
>
> >> class ReversedSorted(Reversed, Sorted):
> >>     pass
>
> >> if __name__ == '__main__':
> >>     words = 'this is a test'.split()
> >>     print SortedReversed(words).join()
> >>     print ReversedSorted(words).join()
>
> >> So I'm wondering, is the decorator pattern applicable here ? If yes,
> >> how ? If not, is there another way to convert inheritance to
> >> delegation ?
>
> > Factory - and dynamic subclassing, as shown here:
>
> > import random
>
> > class A(object):
> >      pass
>
> > class B(object):
> >      pass
>
> > def create_instance():
> >      superclasses = tuple(random.sample([A, B], random.randint(1, 2)))
> >      class BaseCombiner(type):
>
> >          def __new__(mcs, name, bases, d):
> >              bases = superclasses + bases
> >              return type(name, bases, d)
>
> >      class Foo(object):
> >          __metaclass__ = BaseCombiner
> >      return Foo()
>
> > for _ in xrange(10):
> >      f = create_instance()
> >      print f.__class__.__bases__
>
> Right now I see of course that I could have spared myself the whole
> __metaclass__-business and directly used type()... Oh well, but at least it
> worked :)
>
> Diez


Ok, I see how this would work (and it's trivial to make it cache the
generated classes for future use) but I guess I was looking for a more
"mainstream" approach, something that even a primitive statically
typed language could run :) Even in Python though, I think of Runtime
Type Generation like eval(); it's good that it exists but it should be
used as a last resort. Also RTG doesn't play well with pickling.

Since I don't have many useful subclasses so far, I'll stick with
explicit inheritance for now but I'll consider RTG if the number of
combinations becomes a real issue.

George



More information about the Python-list mailing list