Overriding methods in classes you don't control

A

Alex VanderWoude

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.

Now I can do this since I have access to the wxPython source code. However,
I would prefer to have some generalized way of grabbing the original code
and inserting it where that middle comment is. That way, my enhancements
will continue to work even with other versions of wxPython (assuming of
course that my enhancements don't rely on anything in the original code,
which they don't).

Or am I barking up the wrong tree entirely?

- Alex
 
S

Steven Bethard

Alex said:
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.

Maybe you can do something like:

oldinit = wxFrame.__init__
def newinit(self, *args, **kwargs):
# Some enhancements here.
oldinit(self, *args, **kwargs)
# Some more enhancements here.
wxFrame.__init__ = newinit

that is, save the old __init__ method so that it can be accessed from
within your new __init__ method.

STeVe
 
J

John Roth

Look up "Aspect Oriented Programming" and Python.
You should find several packages that can do this,
together with discussions of how to make cuts and all
that fun stuff. The feeling of power is very heady - until
you have to maintain the resulting mess.

John Roth
 
R

runsun pan

Some untested idea:

1. find what is the base class of wxPython
2. x= subclass from that base class
3. make wxPython.__base__ = x

Don't know if this works, but this is what I would try if I were u
('cos its ease).
 
A

andybak

I've also come across several situations where modifying existing
classes seems the simplest and most intuitive thing to do.

Obviously it is fine for quick hacks but people tend to go 'whoooooo'
and wave their fingers around when people suggest it as a general
technique.

Has anyone got any experience of doing this on medium-size projects and
how quickly things descend into an unmaintainable mess?

What are the specific problems and can they be avoided/worked around?

I suppose the main thing is the problems it causes for other people
reading your source code i.e. how are they supposed to know that Class
X now has some of your code injected into it. And thinking about it.
How are you supposed to remember 3 months down the line!

Maybe a 'best practises' system where any such modifications were made
or mentioned right at the start of the source tree or in a distinctly
named module could alleviate this?
 
A

Amaury Forgeot d'Arc

Alex VanderWoude a écrit :
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.

Sorry, but this won't work with wxPython.
wxPython classes are just wrappers around C++ classes.

You may well replace wxFrame.__init__ with your own method, but it won't
be called by wxMDIParentFrame: wxMDIParentFrame.__init__ directly calls
the C++ constructor, completely ignoring wxFrame.__init__.
The call to the superclass' constructor is done in C++.

Since replacing C++ method is much more difficult (if possible at all),
I'm afraid you will have to do the replacement you plan for every
derived class.

Amaury.
 
A

Amaury Forgeot d'Arc

Alex VanderWoude a écrit :
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.

Sorry, but this won't work with wxPython.
wxPython classes are just wrappers around C++ classes.

You may well replace wxFrame.__init__ with your own method, but it won't
be called by wxMDIParentFrame: wxMDIParentFrame.__init__ directly calls
the C++ constructor, completely ignoring wxFrame.__init__.
The call to the superclass' constructor is done in C++.

Since replacing C++ method is much more difficult (if possible at all),
I'm afraid you will have to do the replacement you plan for every
derived class.

Amaury.
 

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
473,754
Messages
2,569,528
Members
45,000
Latest member
MurrayKeync

Latest Threads

Top