Ruby has a nice, but very dangerous feature called open classes. That means you can extend any class definition if you want it.
This example shows it
#!/usr/bin/ruby class Foo def do_foo return "foo" end end aFoo = Foo.new() puts aFoo.do_foo() class Foo def do_bar return "bar" end end puts aFoo.do_bar()
That means you dynamically extend the definition of Foo class, so the last line prints “bar”.
Python behavior is different, because it does not allows this extending. Python just redefines a class Foo, so new instance of Foo will have a do_bar method only. But this not affected an existing ones, like Ruby does.
class Foo: def do_foo(self): return "foo" aFoo1 = Foo() class Bar(Foo): def do_nothing(self): pass print issubclass(Bar, Foo) print isinstance(aFoo1, Foo) class Foo: def do_bar(self): return "bar" aFoo2 = Foo() aBar = Bar() print issubclass(Bar, Foo) print isinstance(aFoo1, Foo) print isinstance(aFoo2, Foo) print dir(aFoo1) print dir(aFoo2) print dir(aBar)
But what about method injection? My solution is based on ideas of Recipe 81732: Dynamically added methods to a class.
import types def funcToMethod(func, instance, method_name=None): cls = instance.__class__ if type(instance) != types.TypeType else instance setattr(cls, \ method_name or func.__name__, \ types.MethodType(func, instance, cls))
And that’s all. The funcToMethod bounds func to instances’s class and allows under method_name (default name is a same as a function one). So lets do some testing.
class Foo(object): def list(self): return [meth for meth in dir(self) if meth[:3] == 'do_' and type(getattr(self, meth)) == types.MethodType] def do_bar(self): return "bar" def do_foo(inst): return "foo" class Bar(Foo): def do_nothing(self): pass aBar = Bar() aFoo1 = Foo() print aFoo1.list() # calling it with class instead of instance is also possible and is equivalent #funcToMethod(do_foo, Foo, "do_foo") funcToMethod(do_foo, aFoo1, "do_foo") aFoo2 = Foo() print aFoo1.list() print aFoo2.list() print aFoo1.do_foo() print aFoo2.do_foo() print aBar.list() print aBar.do_foo()
When you run the code, you will see that funcToMethod adds a new method to Foo class and this changes both existing and new instances as Ruby does too. And subclassing is not a problem, they are be affected too.