multiple extensions to a class

H

Humpty Dumpty

Hello, I'm experimenting with different ways of extending a class (for a
plug-ins framework for a GUI) with more than one extension when some of
these extensions need to collaborate, but others mustn't know about each
other.

I.e., if I have a class A, and I want to add a block of functionality, I
can derive it into a B that adds that fucntionality. If I want to add more
functionality, I can derive B into a C. But if I want to add a third bit of
functionality D directly to A, such that D knows nothing about B or C, I
won't be able to instantiate an object that has all three extensions, namely
an "ABCD". It will either be an "ABC" or an "AD".

One possibility would be to define the extensions B,C and D as functions and
add those functions to A with new.instancemethod. Any other ideas on how to
do this? E.g. is it possible to *add* base classes to a class? I could add
the extensions by adding them as base classes to A.

Thanks,
Oliver
 
D

David Fraser

Humpty said:
Hello, I'm experimenting with different ways of extending a class (for a
plug-ins framework for a GUI) with more than one extension when some of
these extensions need to collaborate, but others mustn't know about each
other.

I.e., if I have a class A, and I want to add a block of functionality, I
can derive it into a B that adds that fucntionality. If I want to add more
functionality, I can derive B into a C. But if I want to add a third bit of
functionality D directly to A, such that D knows nothing about B or C, I
won't be able to instantiate an object that has all three extensions, namely
an "ABCD". It will either be an "ABC" or an "AD".

One possibility would be to define the extensions B,C and D as functions and
add those functions to A with new.instancemethod. Any other ideas on how to
do this? E.g. is it possible to *add* base classes to a class? I could add
the extensions by adding them as base classes to A.

Thanks,
Oliver

I do a template class using a function:

def B(baseclass):
class B(baseclass):
def f(self, x, y):
# do stuff
super(B, self).f(x, y)
return B

def C(baseclass):
class C(baseclass):
def f(self, x, y):
# do stuff
super(C, self).f(x, y)
return C

extendedA = C(B(A))
extendedA.f(3,4)

I think you can find recipes like this in the Python cookbook...

David
 
J

Jeff Shannon

Humpty said:
One possibility would be to define the extensions B,C and D as functions and
add those functions to A with new.instancemethod. Any other ideas on how to
do this? E.g. is it possible to *add* base classes to a class? I could add
the extensions by adding them as base classes to A.

You might consider making class A into a container of some sort -- i.e.,
give it someplace to store a list of "decorator" objects, and then make
B, C, and D into such decorators (rather than subclasses of A). You'll
have to arrange some way of dispatching messages to A that are intended
for the decorators, and possibly some way for the decorators to talk to
each other. (It's hard to say whether you'd be better off making B and
C separate decorators, or whether to subclass C from B -- depends on
your specific application.)

Jeff Shannon
Technician/Programmer
Credit International
 
D

David Fraser

Jeff said:
You might consider making class A into a container of some sort -- i.e.,
give it someplace to store a list of "decorator" objects, and then make
B, C, and D into such decorators (rather than subclasses of A). You'll
have to arrange some way of dispatching messages to A that are intended
for the decorators, and possibly some way for the decorators to talk to
each other. (It's hard to say whether you'd be better off making B and
C separate decorators, or whether to subclass C from B -- depends on
your specific application.)
The advantage of Python here is that you don't need to subclass one from
the other - just make a clear definition of the methods you expect, and
then have a system where you call methods on a list of listening classes...

David
 
M

Michele Simionato

Humpty Dumpty said:
Hello, I'm experimenting with different ways of extending a class (for a
plug-ins framework for a GUI) with more than one extension when some of
these extensions need to collaborate, but others mustn't know about each
other.

I.e., if I have a class A, and I want to add a block of functionality, I
can derive it into a B that adds that fucntionality. If I want to add more
functionality, I can derive B into a C. But if I want to add a third bit of
functionality D directly to A, such that D knows nothing about B or C, I
won't be able to instantiate an object that has all three extensions, namely
an "ABCD". It will either be an "ABC" or an "AD".

One possibility would be to define the extensions B,C and D as functions and
add those functions to A with new.instancemethod. Any other ideas on how to
do this? E.g. is it possible to *add* base classes to a class? I could add
the extensions by adding them as base classes to A.

Thanks,
Oliver

I am not sure about your question. It seems you want mixins. Do you want
the ability to add a plugin dynamically and add new methods to all
your objects at run-time, including previously instanced objects?
It can be done. Or maybe you want to decide the plugins to use at import
time, i.e. you want "import_with_metaclass". In this case you may
google this newgroup and look at this article:

http://www-106.ibm.com/developerworks/library/l-pymeta.html

(there is also a second one http://www-106.ibm.com/developerworks/library/l-pymeta2)

HTH,

Michele Simionato
 
P

Peter Otten

Humpty said:
I.e., if I have a class A, and I want to add a block of functionality, I
can derive it into a B that adds that fucntionality. If I want to add more
functionality, I can derive B into a C. But if I want to add a third bit
of functionality D directly to A, such that D knows nothing about B or C,
I won't be able to instantiate an object that has all three extensions,
namely an "ABCD". It will either be an "ABC" or an "AD".

This sounds like the following inheritance tree would be the obvious answer:

class A: pass
class B: pass
class C: pass
class D: pass

class AB(A, B): pass
class ABC(A, B, C): pass
class AD(A, D): pass

I may still be misunderstanding something...

Peter
 
J

John Lenton

Hello, I'm experimenting with different ways of extending a class (for a
plug-ins framework for a GUI) with more than one extension when some of
these extensions need to collaborate, but others mustn't know about each
other.

I.e., if I have a class A, and I want to add a block of functionality, I
can derive it into a B that adds that fucntionality. If I want to add more
functionality, I can derive B into a C. But if I want to add a third bit of
functionality D directly to A, such that D knows nothing about B or C, I
won't be able to instantiate an object that has all three extensions, namely
an "ABCD". It will either be an "ABC" or an "AD".

One possibility would be to define the extensions B,C and D as functions and
add those functions to A with new.instancemethod. Any other ideas on how to
do this? E.g. is it possible to *add* base classes to a class? I could add
the extensions by adding them as base classes to A.

maybe I'm missing something, but wouldn't a class E(ABC, AD) work?
 
H

Humpty Dumpty

From: "John Lenton said:
maybe I'm missing something, but wouldn't a class E(ABC, AD) work?


No because B,C and D are discovered at run-time only, ie class E can't be
known until runtime. You'd have to create a string with the code and use
exec or eval or s/t similar.

Oliver
 
H

Humpty Dumpty

Peter Otten said:
This sounds like the following inheritance tree would be the obvious answer:

class A: pass
class B: pass
class C: pass
class D: pass

class AB(A, B): pass
class ABC(A, B, C): pass
class AD(A, D): pass

Which one offers "ABCD"? Plus, as I just mentioned in a reply to another
poster in this thread, B,C and D are discovered at run-time so anything
based on class Something(derived from combination of A,B,C,D) is doomed
since derivation is not dynamic.

Oliver
 
H

Humpty Dumpty

Interesting idea, could be done... how does this differ from the mixin
approach?


I could probably create a forwarding mechanism so that if a class doesn't
understand something, it passes on the request to each decorator in a list.
Then C could just be a decorator of B, just like B is of A.
The advantage of Python here is that you don't need to subclass one from
the other - just make a clear definition of the methods you expect, and
then have a system where you call methods on a list of listening
classes...


Yes, but you have to be careful with that in terms of cohesion: though you
want to allow for extendability through plug-ins, you don't want to
encourage a mish mash of unrelated classes that send messages around. It's a
technique to keep in mind, but I want to maintain aggregation of logic and
function and data as much as possible, ie aim for "the right balance" :)

Oliver
 
M

Michele Simionato

Humpty Dumpty said:
No because B,C and D are discovered at run-time only, ie class E can't be
known until runtime. You'd have to create a string with the code and use
exec or eval or s/t similar.

Not at all. You can create classes at run-time with "type":

type("MyDynamicClass",bases_set_at_run_time,dict_set_at_run_time)

Michele Simionato
 
P

Peter Otten

Humpty said:
Which one offers "ABCD"? Plus, as I just mentioned in a reply to another
poster in this thread, B,C and D are discovered at run-time so anything
based on class Something(derived from combination of A,B,C,D) is doomed
since derivation is not dynamic.

The idea was that the classes you would actually use are arbitrary
combinations of "partial implementation" classes that bear no inheritance
relationships.
Seems like I misunderstood your problem and you were after the technical
means to perform this combination at runtime. - Michele has just shown how
to achieve that with type().

Peter
 
J

Jeff Shannon

Humpty said:
From: "David Fraser" <[email protected]>




Interesting idea, could be done... how does this differ from the mixin
approach?

Mixins are all derived from the parent class. Combining multiple mixins
requires (as you've noted) knowing ahead of time which combinations
you'll need, and creating a derived class that includes all of the
necessary mixins. (Python does include enough facilities that you could
do this at runtime, but I'm personally rather leery about using this
level of deep magic unless it's truly necessary.)

Decorators, on the other hand, are designed to work with a particular
class, but are not linked directly in an inheritance tree. There might
be a fair amount of coupling between the decorator and the class that
it's designed to decorate, but not necessarily. (IIRC, the Gang of Four
used an example based on a windowing toolkit -- a "border" class could
be designed as a decorator; it wouldn't care what variety of "window"
class it was decorating, and the "window" class wouldn't care what
variety of "border" it carried. The communication protocol between them
would be fairly straightforward and wouldn't depend on the specific
implementation of either the decorator or the decorated class.)
Yes, but you have to be careful with that in terms of cohesion: though you
want to allow for extendability through plug-ins, you don't want to
encourage a mish mash of unrelated classes that send messages around. It's a
technique to keep in mind, but I want to maintain aggregation of logic and
function and data as much as possible, ie aim for "the right balance" :)

Definitely a balance to be had, here. On the whole, though, I don't see
an overgrown inheritance tree to be more maintainable than coherent set
of decorators. Whether the classes are related or not makes scant
difference when there's a mish-mash of them sending messages around. ;)
To my mind, an inherited mixin class is conceptually no simpler than an
aggreggated helper class, and depending on the specific application
aggreggated helpers may result in a cleaner, less-cluttered design. In
particular, for the case where varying sets of additional features will
be needed and those needs won't be known until runtime (i.e., your
case), aggreggation is better able to deal with the dynamic nature of
the requirements.

What I'm envisioning is a system wherein class A contains a list of
decorators. You could probably add and remove decorators at will;
certainly it'd be trivial to pass a list of decorators when A is
instantiated. Now, whenever a significant state change occurs in A, it
will iterate over that list, calling a generic method on each decorator
and passing itself as a parameter:

for dec in self.decorators:
dec.Go(self)

Then the Go() method on each decorator can inspect class A for the
attributes that it understands, and act on them as appropriate. This
does require some coupling between A and the decorators, as they must
both follow a particular protocol, but it doesn't require that either
side of the protocol be a specific class. This means that if you later
extend A in another way, all subclasses of A will work with the same set
of decorators that A does... and a complete replacement for A, not
rooted in the same inheritance tree, will work just as well.

Jeff Shannon
Technician/Programmer
Credit International
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,202
Messages
2,571,057
Members
47,661
Latest member
sxarexu

Latest Threads

Top