This is a concept that I’ve encountered over and over, mostly while writing unit tests. Every time it has crossed my plate, I’ve looked at code like this:
Python 2.5.1 (r251:54863, Apr 15 2008, 22:57:26) [GCC 4.0.1 (Apple Inc. build 5465)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> class A(object): ... def boo(self): ... print "boo" ... >>> def foo(self): ... print "foo" ... >>> a = A() >>> a.boo <bound method A.boo of <__main__.A object at 0x819b0>> >>> a.boo = foo >>> a.boo <function foo at 0x7ea70>
And have come to a conclusion like “well, there’s a difference between bound methods and normal functions”. Then I end up on a wild goose chase, looking at classes and stuff:
>>> b = A() >>> b.boo <bound method A.boo of <__main__.A object at 0x818f0>> >>> b.boo.__class__ <type 'instancemethod'> >>> foo.__class__ <type 'function'> >>>
From here, I reach the conclusion that I need to figure out how to instantiate an ‘instancemethod’. On previous days, this has led to frustration — but not today! Finally today, with the help of Ryan Baldwin, I feel satisfied that I understand one more aspect of Python.
First, by looking at the ‘instancemethod’ object, you can see that there’s three attributes: ‘im_class’, ‘im_func’, and ‘im_self’.
>>> dir(b.boo) ['__call__', '__class__', '__cmp__', '__delattr__', '__doc__', '__get__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'im_class', 'im_func', 'im_self']
This makes sense — a bound ‘instancemethod’ need to have access to its function object (im_func), its instance (im_self), and its containing class (im_class). So my first attempt was to just swap out the im_func:
>>> b.boo.im_func = foo Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: readonly attribute
Well then. Looks like that won’t work.
Some Googling got me to http://docs.python.org/library/types.html#module-types, where all was revealed.
The types module has a MethodType object, that takes three parameters: types.MethodType(function, instance, class). That sure sounds like the parameters on an ‘instancemethod’ from above.
>>> import types >>> b.boo = types.MethodType(foo, b, A) >>> b.boo() foo