multiple inheritance of a dynamic list of classes?

Peter Otten __peter__ at web.de
Tue Feb 13 06:46:25 EST 2007


devicerandom at gmail.com wrote:

> On 13 Feb, 09:14, Peter Otten <__pete... at web.de> wrote:
>> deviceran... at gmail.com wrote:
>> > Thanks both for suggestions. I still think that using inheritance is
>> > somehow cleanest in this case (I always hear the mantra "avoid
>> > multiple inheritance!", but this is one of the cases it seems to make
>> > a lot of sense to me), but it's nice food for thought/code anyway.
>>
>> "Avoid inheritance" would be almost as justified :-)
> 
> Why?

Well, what problems ocurring with

class A: pass
class B: pass
class C(A, B): pass

could be avoided by writing

class A: pass
class B(A): pass
class C(B): pass

instead? Classes have to be designed for subclassing, so essentially you get
two interfaces, one for subclasses and one for client code instead of just
the latter. A more relevant mantra governing inheritance is "Flat is better
than nested".

>> Problems that may arise with this case of multiple inheritance:
>>
>> - If you need initializers, ensure that they are all invoked
> 
> Yes, I figured it out. This should be easy in this case.
> 
>> - What would you do about name clashes? To avoid them your plugins need
>> to know about each other.
> 
> Yes, I know, but I can't see any simple solution to this (if you can,
> please share it with me!). The cmd module works by interpreting any
> method starting with "do_" as a command, so "do_blah" becomes the
> "blah" command. If two people write a "do_blah" command, and both
> plugins are used, I see no easy way to solve the issue (apart
> rewriting a cmd module).
> Perhaps there can be some previous sanity check in each modules dict
> to see if there are obvious namespace clashings, and in this case
> issue a warning. I don't know.
> 
>> - State (instance attributes) is shared among all your plugins. Since you
>> call all base classes Commands, Python's double-underscore hack won't
>> work.
> 
> What double-underscore hack are you referring to? (sigh, my python
> limits are all arising...) I can call all base classes
> PluginNameCommand, however, this wouldn't break the thing (I'm still
> at the very early planning stage) and would maybe work.

If you use attributes starting with two underscores inside a method, Python
transparently prepends them with the class name. This allows to you to use
the same variable name in two base classes and reduces coupling:

>>> class A:
...     def set_a(self, v): self.__value = v
...
>>> class B:
...     def set_b(self, v): self.__value = v
...
>>> class C(A, B): pass
...
>>> c = C()
>>> c.set_a("alpha"); c.set_b("beta")
>>> vars(c)
{'_A__value': 'alpha', '_B__value': 'beta'}

But if two classes with the same name use the "private" variable, the
mechanism fails:

>>> OldA = A
>>> class A:
...     def set_b(self, v): self.__value = v
...
>>> class C(A, OldA): pass
...
>>> c = C()
>>> c.set_a("alpha"); c.set_b("beta")
>>> vars(c)
{'_A__value': 'beta'}

Peter



More information about the Python-list mailing list