[Python-3000] Method to populate tp_* slots via getattr()?

Nick Coghlan ncoghlan at gmail.com
Tue Apr 8 18:45:54 CEST 2008


Guido van Rossum wrote:
> I'll wait for others to jump on this bandwagon... IMO the tempfile
> object would be better off not to bother with caching at all...

I may have found a slightly more convincing example after spending a 
fairly enlightening evening browsing through the source code for
weakref.proxy. The way that code works is to define every slot,
delegating to the proxied object to handle each call (wrapping and
unwrapping the proxied object as needed).

This is normally transparent to the user due to the fact that
__getattribute__ is one of the proxied methods (and at the C level, the
delegated slot invocations return NotImplemented or set the appropriate
exceptions). The only way it shows through is the fact that
operator.isNumber and operator.isMapping will always return True for the
proxy instance, and operator.isSequence will always return False - this
is due to the proxy type filling in the number and mapping slots, but
not the sequence slots. (Are isMapping, isNumber and isSequence slated 
for the chopping block in the stdlib reorg? If they aren't yet, the 
probably should be)

The weakref.proxy function actually goes to some additional effort to 
get callable() to return the right answer by using a different type (one 
with an empty tp_call slot) when the object being weak referenced 
doesn't define __callable__ (the two separate weakref proxy types 
actually still exist in Py3k, despite the removal of callable).



However, all this prompted me to try an experiment (Python 2.5.1), and 
the results didn't fill me with confidence regarding the approach of
expecting 3rd party developers to explicitly delegate all of the special
methods themselves:

 >>> class Demo:
...   def __index__(self):
...     return 1
...
 >>> a = Demo()
 >>> b = weakref.proxy(a)
 >>> operator.index(a)
1
 >>> operator.index(b)
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
TypeError: 'weakproxy' object cannot be interpreted as an index

Oops, we didn't even catch that missing delegation in our *own* proxy 
implementation when __index__ was added, let alone anyone else's. (I've 
now raised this missing delegation as issue 2592)

With the 2.x approach of using a classic class to implement delegation 
via __getattr__ (since classic classes are special-cased everywhere to 
go through that hook, even from C code) being removed in Py3k, it would 
probably be a worthwhile project to take the weakref.proxy code and come 
up with an equivalent version that retained a strong reference to the 
original object and was able to be subclassed (weakref.proxy doesn't 
permit subclasses).

I'd expect including a pure Python version of this would be better than 
writing it in C:
- It will be a lot easier to write and maintain
- It will still be faster than using a classic class would have been
- Being written in Python allows it to be a pure mixin class that won't 
restrict a subclass's ability to inherit from a class written in C
- By having a full proxy implementation in the standard library, third 
party developers can check that their own proxy implementations are 
explicitly delegating at least the same range of special methods as the 
standard library implementation.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
---------------------------------------------------------------
             http://www.boredomandlaziness.org


More information about the Python-3000 mailing list