Ruby Style Adding Methods to Existing Classes in Python?
For some reason I’m getting interested in the idea of adding methods to existing classes at runtime as opposed to inheriting from and extending classes. I can’t put my finger on why, but inheritence is slowly losing its luster for me.
From the little bit of poking around in Ruby I’ve done, I know this is possible. In fact, you can do all kinds of funky things like add a method to a single instance of a class.
These days, however, I’m in Python land, and I’m just getting productive enough not want to jump ship.
So, my questions are:
- Is there a way to do Ruby-style injection-of-methods-into-existing-classes in Python?
- Is there a name for this style?
- Why am I losing faith in inheritence? This is disturbing me; I used to teach a class on OOP and point to inheritence as a valuable and nice thing.
- Is this idea of adding methods to existing classes/instances actually a bad idea? I’ve run into several posts claiming so, but I haven’t seen evidence or examples.
- Is injection of methods into a class equivalent to inheriting from it and extending it?
Poking around a bit I come across a Python cookbook recipe for doing this, but that doesn’t look very clean.
I’d really like to try this out and see if it is a bad idea. Am I going to have to learn Ruby to do it?
UPDATE: From the comments, a Nice example of how to do this from Harry Feucks (turns out it’s pretty simple) and a more sophisticated example and decorator from Ian Bicking. Also, interesting discussion on this topic from the Ruby heads over on RedHanded, where we seemed to have coined guerillapatching as the name of this technique.
Manage your expenses via Email, SMS, Twitter, Voice (Jott: Call and say your expense), IM (Yahoo, AIM, MSN), or Web.
I haven’t played with this kind of thing myself, but it looks like the comments attached to that cookbook entry (in particular Alex Martelli’s usage of the ‘new’ module) describe the “correct” approach. Ruby certainly makes it easier to do this though - it’s a common idiom in Ruby, but quite rare in Python.
Interested to know the ins and outs here as well.
Think it needs careful definition of different things you can do - adding a method to a class at runtime is not the same as adding a method to an object (an instance of the class). That “new” approach seems to address the latter.
The former is fairly easy e.g.
class Foo:
def __init__(self):
self.x = “x = 1″
self.y = “y = 2″
def showx(self):
print self.x
def showy(self):
print self.y
if __name__ == ‘__main__’:
# Attach at runtime…
Foo.showy = showy
f2 = Foo()
f2.showx()
f2.showy()
Now all instances of Foo, created _after_ attaching showy, have this method available. The downside there is the definition of showy has “self” embedded - it can’t also just be a function but perhaps that’s a rare requirement.
“Why am I losing faith in inheritence?” the desire to avoid rigid code, gain more flexibility and (perhaps) save time?
“Is this idea of adding methods to existing classes/instances actually a bad idea?” I guess three possible issues (but not show stoppers) might be;
- it’s potentially expensive performance wise - if you’re doing this a lot, you might have missed the chance save some cycles by hardcoding, allowing python to compile upfront
- it’s harder to analyse the source code automatically and understand it’s semantics, without actually executing it
- it’s (subjective) easier for teams of developers to working with concrete / static class definitions. I find this discussion relevant: http://groups.yahoo.com/group/wdf-dom/message/4136&threaded=1 - although that’s Javascript, think it applies
“Is injection of methods into a class equivalent to inheriting from it and extending it?” - does the question matter? Think inheritance is Python is more of a notionally supported feature than something rock solid, as in Java. You have multiple inheritance. You have explicit self rather than implicit “this”. It’s more like - what’s the easiest way to get re-use?
Sorry - further point on that link http://groups.yahoo.com/group/wdf-dom/message/4136&threaded=1 - it’s the section “8. JavaScript is too flexible” I was referring to
Harry, much thanks, your example is very helpful. It *is* quite easy to add methods to existing classes in Python. The formatting was lost on your post, so I’ve uploaded the file here (since formatting matters so much in this example).
Regarding the Javascript example, wow, 60,000 lines of Javascript. I wouldn’t wish that on my worst enemy.
“I find myself wishing for build-time tools, a compiler to catch typos in
variable names, to catch syntax errors earlier rather than runtime
checking.”
This argument can be applied to any scripting language. I think Javascript is a particularly horrible language and I’d tend to lay the blame there as opposed to compile time rather than runtime enforcement of syntax, etc.
The following blog post I wrote quite some time ago relates to your question:
http://www.daniel-lemire.com/blog/archives/2005/12/21/metaclass-programming-in-python/
A possibly handy little decorator for injection methods that I wrote is magic_set at the bottom of this file: http://svn.colorstudy.com/home/ianb/ruby_blocks.py