[Python-3000] Bound and unbound methods
Nick Coghlan
ncoghlan at gmail.com
Fri Aug 18 17:14:16 CEST 2006
Guido van Rossum wrote:
>> Would a possible special method name __methodcall__ be accepted, where
>> if it exists on a callable, you can expect to use it as __call__ but
>> with the understanding that it accepts <expr> as self when called in
>> an optimizable form? This would reduce the method call to two
>> attribute lookups before the call instead of an instansiation and all
>> the heavy lifting currently done. For normal functions,
>> 'f.__methodcall__ is f.__call__' may be true, but the existance of
>> that __methodcall__ name just gives you an extra contract.
>
> I'd like to answer "no" (since I think this whole idea is not a very
> fruitful avenue) but frankly, I have no idea what you are trying to
> describe. Are you even aware of the descriptor protocol (__get__) and
> how it's used to create a bound method (or something else)?
>
> No reply is needed.
If I understand Calvin right, the best speed up we could get for the status
quo is for the "METHOD_CALL" opcode to:
1. Do a lookup that bypasses the descriptor machinery (i.e. any __get__
methods are not called at this point)
2. If the object is a function object, invoke __call__ directly, supplying
the instance as the first argument
3. If the object is a classmethod object, invoke __call__ directly,
supplying the class as the first argument
4. If the object is a staticmethod object, invoke __call__ directly,
without supplying any extra arguments
5. If the object has a __get__ method, call it and invoke __call__ on the
result
6. Otherwise, invoke __call__ on the object
(Caveat: this omits details of the lookup process regarding how descriptors
are handled that an actual implementation would need to deal with).
I think what Calvin is suggesting is, instead of embedding all those special
cases in the op code, allow a descriptor to define __methodcall__ as an
optimised combination of calling __get__ and then invoking __call__ on the
result. Then the sequence of events in the op code would be to:
1. Do a lookup that bypasses the descriptor machinery
2. If the object defines it, invoke __methodcall__ directly, supplying the
instance as the first argument and the class as the second argument (similar
to __get__), followed by the args tuple as the 3rd argument and the keyword
dictionary as the 4th argument.
5. If the object doesn't define __methodcall__, but has a __get__ method,
then call it and invoke __call__ on the result
6. Otherwise, invoke __call__ on the returned object
For example, on a function object, __methodcall__ would look like:
def __methodcall__(self, obj, cls, args, kwds):
if obj is None:
raise TypeError("Cannot call unbound method")
return self(obj, *args, **kwds)
On a class method descriptor:
def __methodcall__(self, obj, cls, args, kwds):
return self._function(cls, *args, **kwds)
On a static method descriptor:
def __methodcall__(self, obj, cls, args, kwds):
return self._function(*args, **kwds)
Cheers,
Nick.
--
Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
---------------------------------------------------------------
http://www.boredomandlaziness.org
More information about the Python-3000
mailing list