Overriding methods in classes you don't control

Alex VanderWoude nospam at biteme.com
Mon Mar 28 21:10:38 EST 2005


"Jp Calderone" <exarkun at divmod.com> wrote in message
news:mailman.937.1111985880.1799.python-list at python.org...
> On Mon, 28 Mar 2005 03:57:16 GMT, Alex VanderWoude <nospam at biteme.com>
wrote:
> >Is there a way to override a method on a class whose source you cannot
> > change in such a way that you can hook into that method's code?  After
doing
> > some research, it appears that one way to do such a thing is to create a
new
> > (non-class) method, and then assign the new method to the class in
question,
> > thus replacing the existing class method.  However, I have read vague
hints
> > in the documentation that this is not a good thing to do (?).
Furthermore,
> > you probably need access to the source code of the method you are
replacing
> > so that you can duplicate and modify it in your method.  Now in this
> > particular case that is true, but what I really want to know is whether
or
> > not there is an accepted Pythonic way to do this.
> >
> > Here's the situation.  I'm using wxPython, and I want to make an
enhancement
> > in the __init__ method of all the frame classes. The ideal place to do
this
> > is in wxFrame.__init__, since any change there will automatically be
> > inherited by the other frame classes (for example, wxMDIParentFrame).
> > Obviously I can inherit from wxPython and make the changes in my
subclass,
> > but then I would have to also subclass wxMDIParentFrame and duplicate my
> > enhancements there, and then use only my subclasses rather than the
wx***
> > classes.
> >
> > Basically I want to change wxFrame.__init__ so that it looks sort of
like
> > this:
> >
> >     def __init__(self, *args, **kwargs):
> >         # Some enhancements here.
> >         # The original code of this method, including the call to its
> > ancestor.
> >         # Some more enhancements here.
> >
> > And then I can replace wxFrame's __init__ with my new version by
assigning
> > it before any frames are instantiated.
>
>     from thirdparty.project import Something
>
>     orig = Something.meth
>     def new(x, y, z):
>         foo()
>         orig(x, y, z)
>         bar()
>     Something.meth = new
>
>   HTH,
>
>   Jp

Well I'll be, that works:

IDLE 1.0.2
>>> class FooAncestor(object):
    def Bar(self):
        print "Now in FooAncestor.Bar()"

>>> class FooDescendant(FooAncestor):
    def Bar(self):
        print "Now in FooDescendant.Bar()"
        FooAncestor.Bar(self)
        print "Back in FooDescendant.Bar()"

>>> OldBar = FooAncestor.Bar

>>> def NewBar(self):
    print "Start of NewBar()"
    OldBar(self)
    print "End of NewBar()"

>>> FooAncestor.Bar = NewBar

>>> Foo = FooDescendant()

>>> Foo
<__main__.FooDescendant object at 0x00981F50>

>>> Foo.Bar()
Now in FooDescendant.Bar()
Start of NewBar()
Now in FooAncestor.Bar()
End of NewBar()
Back in FooDescendant.Bar()

It must be because the creation of OldBar() actually instantiates a callable
object using the code found in FooAncestor (which itself has not yet been
instantiated).  This "separates" OldBar() from the FooAncestor.Bar()
definition.  When an instance of FooAncestor (or one of its descendants) is
created then another, different callable object is created as part of the
new class (Foo in the example above).

Thanks to all in this thread for your help.

- Alex






More information about the Python-list mailing list