Creating Python Instance Methods
Ever wondered how would you override an object's method implementation at runtime, using Python? I did and never found a document describing how to do so. So I decided to learn it myself.
Instance methods defined in a class are special types of functions. When a method is called the first argument is the instance associated with it, usually know as self. In languages such as Java or C# it's the special variable this which is implicitly defined by the language. Implicit things are fine and dandy but also decrement the power of a language. In this document I will show you how you can associate override a method at runtime, per class or even per instance.
You can also define functions as a class members, however you must define it after class definition:
class Foo: def a_method (self): print "I'm a method" def a_function (): print "I'm a function" Foo.a_function = a_function
This would map the static modifier used in Java with a little nuance, because there is no real visibility modifiers at class level you wouldn't be able to access a class private variable whereas in Java you could. Python supports multiple heritage so you wouldn't know what is the function context, this is why you can use classmethod where the defined class method recieves the class object as the first argument (cls in oposition to self).
This is fun and all but it doesn't allow us to redefine an instance method. We need something else... If we do a:
print Foo.a_method, type (Foo.a_method) f = Foo () print f.a_method, type (f.a_method) print a_function, type (a_function)
It will print something like this:
<unbound method Foo.a_method>, <type 'instancemethod'> <bound method Foo.a_method of <cool.Foo instance at 0x401d9fcc>>, <type 'instancemethod'> <function a_function at 0x401d5df4>, <type 'function'>
The printed output shows the difference between a function and a method. We observe see the difference between an instancemethod when called from the class context and from the instance context. This is what Python calls bound: bounded instancemethods are ones which are colled from an instance as opposed to unbound which refeer to classes.
Python also allows us to create an object by using it's type. This means that if we do:
f = Foo ()
Is the same thing as:
f_type = type (f)
Which is also the same as:
f_type = Foo
Therefore if we want to create instance method's we just need to grab the type. This couldn't be easier, we just define a class with a single method and keep it's type in a variable we'll call instancemethod.
There is one last problem with this approach: we don't know the constructor's signature of this new type. Well this is the easiest one, because of docstrings we can do a help(instancemethod) and read it how it's done:
instancemethod = type (Foo.a_method) help (instancemethod)
This will show you how to use it (snip):
class instancemethod(object) | instancemethod(function, instance, class) | | Create an instance method object.
Hey after all it's really easy to do it! Here's an example on how everything can be wrapped up:
class Foo: def bar (self): print "Hello from original method", self instancemethod = type (Foo.bar) foo_obj = Foo () # Implement a new method def my_new_method (self): print "Hello from my_new_method of object", self def another_method (self): print "Hello from another_method of object", self # Keep the old method just for fun old_method = foo_obj.bar # Define the new method bound to an object foo_obj.bar = instancemethod (my_new_method, foo_obj, Foo) # Define a new method bound to a class old_foo_obj = Foo () Foo.bar = instancemethod (another_method, None, Foo) new_foo_obj = Foo () # Original method will be called old_method () # We redefined the method, it will be called foo_obj.bar () # We didn't redefined the method of these instances, thus the class definition # will be used new_foo_obj.bar () old_foo_obj.bar ()