[Tutor] Dumb Subclassing question

Alan Gauld alan.gauld at blueyonder.co.uk
Thu Aug 5 22:56:21 CEST 2004


> 'MP3 Tag Studio' and Musicbrainz which between them are a fair bit
more
> powerful than Itunes but I need more power!

Yes, but with iTunes fully scriptable I can pretty much make it do
anything I need - which is very possibly less than you need! :-)

> I mean that any path object returned should have mp3 related
methods.

OK That's what I had assumed,. I just wanted to be sure.

> > No its not decorator and is even more messy!
>
> (unrelated question: How does adding methods to existing instances
differ
> from decorator then?

The decorator is a class that sits in front of another class,
thus decorating it. A big assumption in OO patterns is that the
existing objects can't be changed - because in most languages
they can't! You don't have access to the source in most cases
and you can't dynamically add metjods as you can in Python.

A decorator uses composition as suggested by someone else.
You forward the messages on to the pdeudo parent. The example
given in the Patterns book is that of a scrollable window in
a GUI. The Window class has no scrolling capability but by
wrapping it in a decorator class with scrolling the scroll
message is received by the decorator which adjusts the view
settings of the component window then when the refresh (ie draw)
method is invoked the decorator simply delegates it to the Window.

So from the outside we have a class with scroll and draw methods
but in fact its two classes. Now we could do that with subclassing
so why use decorator? Well what if we have other things we want
to scroll too? We can use our decorator object with any window
like object without having to subclass every widget that might
need scrollers.

> I get the feeling that a lot of common design patterns
> don't apply exactly the same way to Python

They apply the same but Python often has other ways of doing it,
sometimes, but only occasionally,  more neatly.

> Well! You say Yuk but I did a bit more digging and (thanks to Mark
>
Pilgrim:http://diveintomark.org/archives/2003/01/27/dynamically_extend
ing_ap
> is ) found that despite what is implied in the standard library
docs,
> 'instancemethod' will happily add methods to classes. This new
methods then
> get nicely inherited by instances of the class.

But you have still changed the behaviour of an existing class, what
happens when another bit of code creates a path object and expects
the old behaviour? It will get very confused and may do bad things.
And it will be devilishly hard to both tet and debug. Changing
behaviour
at run time should be considered an extremely advanced topic with huge
risks involved. BUT of course if your project is small and you know
exactly what all of the imported objects do then it might be OK. There
are no hard and fast rules.

> This seems cleaner to me than the alternative of overriding all the
methods
> just to add a type wrapper. I'd be interested to know what trouble I
might
> be storing up in terms of bad OO practice...

If you can be sure that nothing in your total code base relies on the
original behaviour, or that you do not significantly (define
significant?!)
change that behaviour you can get away with it, but its exactly the
kind
of change that OOP tries to save you from!

> > So you can write a function that determines the nature of
> > path node you get and only convert the leaf nodes to your
> > class type. That is instead of overriding path to retirn your
> > objects why not get the list of paths back and then convert
> > those as needed to your class?
> >
> Well, the class I am basing myself on doesn't differentiate between
path's
> and filenames and I find that approach fairly nice (only one object
type to
> deal with. Just use .isfile() or isdir() if you need to know).

So it does distinguish between them, it calls the test functions
to determine the difference! So why not use those same functions
to determine when to convert the leaf nodes to your new classes?
Then when you process the list and use the ID3tags method (which
presumably will only be with files) it will be there.

> > for aPath in myPath.files():
> >     if aPath is leaf node  # using isinstance or somesuch?

        if aPath.isfile():   # using your method above

> >        aPath = mp3path(path)
> >        aPath.ID3tag()      # do things with new path object

That way you write a single conversion function and convert the
files you need to convert. No impact on path at all...

You could override the path constructor as suggested elsewhere
but that still potentially breaks existing code by returning a
different kind of object from the one the code expects.

On a final note, it should be realised that OOP does not
automatically imply writing less code. In fact for short programs
it very often means more code, but hopefully the result is both
more maintainable and more robust and flexible.

Alan G.



More information about the Tutor mailing list