How does Subclassing Work?

Alex Martelli aleaxit at yahoo.com
Thu Feb 22 05:36:12 EST 2001


<s713221 at student.gu.edu.au> wrote in message
news:3A943A45.2E433767 at student.gu.edu.au...
> Recently I tried to write a piece of code that subclassed Canvas.py from
> the Tkinter distribution, where I overwrote CanvasItem. Now I was hoping
> that all calls to Arc, Line etc. (which weren't overwritten) would call
> my modified CanvasItem, but it seems they were calling the unmodified
> CanvasItem - which isn't what I wanted.

It's what I would expect, though; the 'class' statement for (e.g.)
Arc was already executed, right when you imported Canvas, and,
at that time, it got the original CanvasItem class to use as the
base -- it didn't get your subclassed version.

> Other than copy all of Canvas.py into my module and redefine everything,
> is there a way I can get this to work as expected without rewriting
> Canvas.py? What I was trying to do was alter Canvas so that I could
> create classes that would make complex items.

I hesitate to suggest it, but... if you went through all the classes
of interest, currently set to inherit from the original CanvasItem,
and changed that portion of their __bases__ to your modified version;
and also set the CanvasItem attribute of the Canvas module to refer
to your modified version; things would probably work as you want.

Here's a toy example to indicate what I mean...:

== Original.py
class OriginalItem:
    def __init__(self, *whatever):
        print "OriginalItem",whatever

class Derived1(OriginalItem):
    def __init__(self, *whatever):
        print "Derived1",whatever
        apply(OriginalItem.__init__, (self,)+whatever)

class Derived2(OriginalItem):
    def __init__(self, *whatever):
        print "Derived2",whatever
        apply(OriginalItem.__init__, (self,)+whatever)
== end

== Tweak.py
import Original

baseClass = Original.OriginalItem
class TweakedItem(baseClass):
    def __init__(self, *whatever):
        print "TweakedItem",whatever

for key,val in Original.__dict__.items():
    if type(val)==type(baseClass):
        if val is baseClass:
            setattr(Original, key, TweakedItem)
        else:
            if val.__bases__ == (baseClass,):
                val.__bases__ = (TweakedItem,)

x = Original.Derived1("foo","bar")
y = Original.Derived2("bar","baz")
== end

This is not very general (though it would suffice for
your specific need), as it only handles single-base
classes etc, but it's not hard to generalize it along
this axis.

I do wonder about the appropriateness of such "black
magick" to actual production code, though.


Alex






More information about the Python-list mailing list