I've moved my blog to jmcneil.net. This is no longer being updated!

Sunday, June 29, 2008

Instance Specific Methods

Given an instance of a Python class, it's quite simple to bind a function to that object. One just binds a callable.

Python 2.5.2 (r252:60911, Apr 21 2008, 11:12:42)
[GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class X(object):
... pass
...
>>> def f():
... pass
...
>>> x = X()
>>> x.f
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'X' object has no attribute 'f'
>>> x.f = f
>>> x.f

>>>

The downside here is that when referencing the newly bound attribute, it's not treated as a bound method but rather a standard function object. There are two simple ways to actually create a new bound method that is specific to an instance.

First, one can easily just call the __get__ method of the function object when binding to the instance. Python functions are non-overriding descriptors. When the __get__ method is called, a method object is returned. Various attributes of the new method object handle the object 'plumbing', so to speak: im_self, im_class, im_func. That's really another topic. Here's how it works:

Python 2.5.2 (r252:60911, Apr 21 2008, 11:12:42)
[GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class X(object): pass
...
>>> def f(self): pass
...
>>> x = X()
>>> x.f
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'X' object has no attribute 'f'
>>> x.f = f.__get__(x, X)
>>> x.f
>
>>>

There we go. The 'im_func' is made available as the first argument to the function's __get__ method, as it is really the 'self' parameter that any standard descriptor would be passed.

The next way to make this all happen is via the types module. There is an 'MethodType' object that we can use to wrap a function:

Python 2.5.2 (r252:60911, Apr 21 2008, 11:12:42)
[GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import types
>>> help (types.MethodType)

>>> class X(object): pass
...
>>> def f(self): pass
...
>>> x = X()
>>> x.f
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'X' object has no attribute 'f'
>>> x.f = types.MethodType(f, x, X)
>>> x.f
>
>>> x.f()
>>>

It's my assumption that MethodType is simply calling f.__get__ internally, though I'm slightly too lazy to go look.

Friday, June 13, 2008

NFS Problems

All of my NFS problems have just gone away. We've recently updated our Kernels to the latest RHES available. Looks like there was something hidden in there that fixed it for us. Wonderful.

I do realize that it's normal to see delay. Both due to attribute cache semantics and mtime granularity of one second. The problem I had here was quite different in that the dentry caches *never* expired negative entries.