Removing inheritance (decorator pattern ?)

Diez B. Roggisch deets at nospam.web.de
Mon Jun 16 11:04:52 CEST 2008


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



More information about the Python-list mailing list