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.