[Python-3000] Bound and unbound methods

Talin talin at acm.org
Sun Aug 13 22:08:10 CEST 2006

Josiah Carlson wrote:
> Talin <talin at acm.org> wrote:
>> One of the items in PEP 3100 is getting rid of unbound methods. I want 
>> to explore a heretical notion, which is getting rid of bound methods as 
>> well.
>> Now, to be honest, I rather like bound methods. I like being able to 
>> capture a method call, store it in a variable, and call it later.
>> However, I also realize that requiring every access to a class variable 
>> to instantiate a new method object is expensive, to say the least.
> Well, it's up-front vs. at-access.  For instances whose methods are
> generally used rarely, the up-front cost of instantiating every method
> is high in comparison (unless there are a relatively large number of
> method accesses), and technically infinite if applied to all objects.
> Why?
> I have a class foo, I instantiate foo, now all of foo's methods get
> instantiated.  Ahh, but foo's methods are also instances of function. It
> doesn't really have any new methods on foo's methods, but they do have
> attributes that are instances, so we will need to instantiate all of the
> methods' attributes' methods, and recursively, to infinity.  The
> non-creation of instantiated methods for objects is a lazy-evaluation
> technique to prevent infinite recursion, in general.
> On the other hand, it may make sense to offer a metaclass and/or
> decorator that signals that a single method instance should be created
> for particular methods up-front, rather than at-access to those methods.
> But what kind of difference could we expect?  42%/28% improvement for
> class methods/object methods in 2.4 respectively, and 45%/26%
> improvement in 2.5 beta .  This does not include actually calling the
> methods.

No, I wasn't proposing that methods be bound up front...read on.

>> Now, one remaining problem to be solved is whether or not to pass 'self' 
>> as an argument to the resulting callable. I suppose that could be 
>> handled by inspecting the attributes of the callable and adding the 
>> extra 'self' argument at the last minute if its not a static method. I 
>> suspect such tests would be relatively fast, much less than the time 
>> needed to instantiate and initialize a new method object.
> I think that a change that required calls of the form
> obj.instancemethod(obj, ...) are non-starters.  

Yes, that's a non-starter, but that's not what I was proposing either.

I see that I left an important piece out of my proposal, which I'll need 
to explain.

Right now, when you say: 'obj.instancemethod()', there are in fact two 
distinct operations going on. The first is the lookup of the attribute 
'instancemethod', and the second is the invoking of the resulting callable.

In order to get rid of the creation of method objects, the compiler 
would have to recognize these two operations and combine them into a 
single "call method" opcode - one which looks up the attribute, but 
leaves the original object pointer on the stack, and then invokes the 
resulting callable, along with the object pointer.

So essentially the 'bind' operation is moved into the method invocation 
code - which eliminates the need to create a holding object to remember 
the binding information.

Hmmmm....I wonder if it could be me made to work in a 
backwards-compatible way. In other words, suppose the existing logic of 
creating a method object were left in place, however the 
'obj.instancemethod()' pattern would bypass all of that. In other words, 
the compiler would note the combination of the attribute access and the 
call, and combine them into an opcode that skips the whole method 
creation step. (Maybe it already does this and I'm just being stupid.)

> I'm -1 for instantiating all methods (for the infinite cost reasons),
> and -1 for int, long, list, tuple, dict, float (method access is
> generally limited for these objects).  I'm +0 for offering a suitable
> metaclass and/or decorator, but believe it would be better suited for
> the Python cookbook, as performance improvements when function calls are
> taken into consideration is significantly less.

Thanks for the timing information by the way.

More information about the Python-3000 mailing list