Re: Removing inheritance (decorator pattern ?)



On Jun 16, 1:49 pm, Gerard flanagan <grflana...@xxxxxxxxx> wrote:

George Sakkis wrote:
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:

I don't know if it will map to your actual problem, but here's a
variation of your toy code. I was thinking the Strategy pattern,
different classes have different initialisation strategies? But then you
could end up with as many Strategy classes as subclasses, I don't know.
(Also in vaguely similar territory -http://bazaar.launchpad.net/~grflanagan/python-rattlebag/trunk/annota...
)

class MetaBase(type):

     def __init__(cls, name, bases, data):
         cls.strategies = []
         cls.prefixes = []
         for base in bases:
             print base
             if hasattr(base, 'strategy'):
                 cls.strategies.append(base.strategy)
             if hasattr(base, 'prefix'):
                 cls.prefixes.append(base.prefix)
         super(MetaBase, cls).__init__(name, bases, data)

class Joinable(object):
     __metaclass__ = MetaBase
     strategy = list
     prefix = ''

     def __init__(self, words):
         self._words = words
         for strategy in self.strategies:
             self._words = strategy(self._words)

     def join(self, delim=','):
         return '%s %s' % (' '.join(self.prefixes), delim.join(self._words))

class Sorted(Joinable):
     strategy = sorted
     prefix = '[sorted]'

class Reversed(Joinable):
     strategy = reversed
     prefix = '[reversed]'

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()

This doesn't solve the original problem, the combinatorial explosion
of empty subclasses. At the end of the day, I'd like a solution that
uses a (mostly) flat, single-inheritance, hierarchy, allowing the
client say:

j = Joinable(words)
if sort:
j = Sorted(j)
if reverse:
j = Reversed(j)
...
print j.join()


George
.



Relevant Pages

  • Re: Removing inheritance (decorator pattern ?)
    ... inheritance but this leads to combinatorial explosion of subclasses as ... Naturally, the decorator pattern ... My multiple inheritance classes though play a double role: ...     pass ...
    (comp.lang.python)
  • Re: Mangle function name with decorator?
    ... possibly by using a decorator to mark them. ...   def foo(... ... dictionary that the metaclass gets only has one one entry, ... def get_only: ...
    (comp.lang.python)
  • Re: doctests and decorators
    ... recommended fix is to update the order of checks in the _from_module ... method of DocTestFinder in the doctest module. ... module of the function object and not of the decorator. ...     return new_function ...
    (comp.lang.python)
  • Re: Removing inheritance (decorator pattern ?)
    ... Naturally, the decorator pattern ... My multiple inheritance classes though play a double role: ... I was thinking the Strategy pattern, ... could end up with as many Strategy classes as subclasses, ...
    (comp.lang.python)
  • Re: creating classes with mix-ins
    ...     class MetaWeblog: ... I'd like to replace the method definitions with a loop: ... Should I use a class decorator, ... returns an object of type Blog, then you could inspect Blog's type ...
    (comp.lang.python)