Ruby has the functionality of being able to add a method to a class at an arbitrary point in your code. I figured Python must have some way for allowing this to happen, and it turned out it did. The method is available instantly to all already existing instances and of course ones yet to be created. If you specify method_name then that name is used for the method call.
One thing to make sure to do is that the function has a variable for the instance to be passed to (i.e. self).
1 2 3 4 5 6 7 8
def funcToMethod(func,clas,method_name=None): """Adds func to class so it is an accessible method; use method_name to specify the name to be used for calling the method. The new method is accessible to any instance immediately.""" func.im_class=clas func.im_func=func func.im_self=None if not method_name: method_name=func.__name__ clas.__dict__[method_name]=func
Why would one use this? I am not completely sure. You could use it as a way to get around having to deal with inheritence. But as I said in the summary, this was mainly to show that it was possible and how flexible Python is.
module new may be preferable. By binding or re-binding attributes of object func, this recipe is fragile -- if funcToMethod is called twice on the same func, confusion is quite possible. Module new is designed to help exactly with such dynamic needs:
A somewhat mind-boggling (or mind-expanding:-) extra of this approach is that func can in fact be any callable, such as an instance of any class that supplies a __call_ special method, or a bound-method...
The 'instancemethod' function name may be slightly misleading: it generates both bound and unbound methods, depending on whether the second argument is None (unbound) or an instance of the class that is the third argument. See http://www.python.org/doc/current/lib/module-new.html for all the details (there's not much more to it than this, though).
Should Have Read the Docs. This is what happens when you get too excited about writing code and don't bother to plan far enough ahead to read the documentation.
Thank you for pointing out the more proper way of handling this, Alex.
Using a function wrapper to automatically provide self to methods added at runtime. The problem with only adding a new function to a class instance's dictionary, is it must always be called in a special manner - it dosn't behave in the same way as normal methods. Using a wrapper class can get round this problem providing a more transparent solution.
The function to be added is say(). The parameter host performs the same purpose as what we normally refer to as self - the object which this method works on. The name host simply reminds us we are parasites in this place!
Synchronizing instance methods. Slight modification to the recipe "9.1 Synchronizing All Methods in an Object." Whereas the the former synchronizes all instances of a class on a single lock, this code synchronizes each instance on it's own lock to makes sure that only one thread at a time has access to certain bound methods. Unsynchronized methods behave normally. Plus, I think this version is more clear.
Just as it is in recipe 9.1 of Python Cookbook, v2
def wrap_callable(any_callable, before, after, new_name=None): """ Wrap any callable with before/after calls """ def _wrapped(args, *kwds): before() try: return any_callable(args, *kwds) finally: after() _wrapped.__name__ = new_name and new_name or any_callable.__name__ return _wrapped
if __name__ == '__main__': import threading, time
def showy(self): print self.y
if __name__ == '__main__':
if I want to use another function than f1
I could also initialize function at class initialisation
but I still will need to pass the class instance as first argument.
tested on python 2.6.2