One of the great features of Python is the ability to define methods outside of classes. For example, we can define a function which increments the attribute
x and add it to a
def incx(self): self.x += 1 class Point(object): def __init__(self, x): self.x = x incx = incx
We can then create a point at the origin and increment
In : p = Point(0) In : p.incx() In : print p.x 1
The same code which defines
Point continues to work if we move
incx to another file, say
demo.py, and import it using
from demo import incx.
But if we were to put
demo.pyx and compile it (using
python setup.py build_ext --inplace), we get a strange error when running our simple test:
$ python bad.py Traceback (most recent call last): File "bad.py", line 10, in <module> p.incx() TypeError: incx() takes exactly one argument (0 given)
Read on to learn about instance methods and see how I fixed this.
My first thought was to write a simple wrapper function, using functools.wraps to preserve the docstring and name. This proved to be a clumsy solution.
A better approach turned out to be to use
types.MethodType to convert our built-in function into an (unbound) instance method. The docstring for
MethodType is pretty short:
instancemethod(function, instance, class)
The first and third arguments are obvious. For the second argument we’ll use
None since we have no instance of the class yet, making this an unbound instance method.
So to fix our simple example, we need only replace the
incx = incx line in the class definition with a short snippet after the class is defined:
from types import MethodType Point.incx = MethodType(incx, None, Point)
We can give this new version a try and see that it works:
$ python good.py
As always, the entire example is available as a Gist.