[Zope3-dev] ContextMethod / Wrapper questions...

Steve Alexander steve@cat-box.net
Fri, 27 Dec 2002 13:14:36 +0000


Brian Lloyd wrote:
> Hi all - 
> 
> I'm working on the C implementation of ContextMethod, etc.,

Cool!
One reason Zope 3 is very slow right now is that lots and lots of things 
go through the __getattribute__ of SimpleMethodWrapper.

This is ok for now, of course, because the alpha release has been 
advertised as being completely unoptimised.


> and I have a few questions for whoever knows the most about this 
> (Steve?).

Me and Jim I think.


> Right now, the Python implementation exposes Wrapper, which 
> is really a function that might return one of 4 subclasses 
> of the real Wrapper, depending on whether the class implements 
> __call__, __getitem__, etc.

Right.


> Is there any reason why we wouldn't want the real Wrapper class 
> to Do The Right Thing if it can tell that a descriptor is a 
> ContextMethod / ContextProperty? That seems like the simplest 
> thing to do, but I wanted to make sure there isn't anything that 
> expects to use the Wrapper C type directly with its current 
> behavior (that doesn't understand descriptors that want context).
> 
> The change would basically be:
> 
>   - add ContextMethod descriptor type

Don't do that. The current way of marking methods as being 
ContextMethods by adding special markers to the method's dict has turned 
out to be really useful. There are other method-like things, such as 
bound ViewPageTemplateFiles that declare the same attributes, so that 
they can be called with a context-wrapped self.


>   - add ContextProperty, ContextGetProperty, ContextSetProperty
>     descriptor types

Again, I don't think this is needed. I think the current way they work 
is ok.


>   - add overrides for the tp_getattro, tp_setattro, tp_call, 
>     mp_subscript, mp_ass_subscript slots on the Wrapper type.
 >
>     These basically just check (efficiently) whether the 
>     attr / slot implementation on the unwrapped object is 
>     a context descriptor,

So, rather than check for a context descriptor, check for the marker 
attributes in the descriptor's dict.


>     and if so passes the wrapped self rather than the stripped self.

Ok. It would be really nice if a wrapper instance could somehow be 
clever, and implement only those C-level slots that the object it wraps 
implements. So, callable(foo) would work properly, and there won't be 
any subtle surprises on whether __len__ or __nonzero__, or __iter__ or 
__getitem__ get called for a wrapped object.

This works for __call__ and __getitem__ in the current python 
implementation.

At the Sprintathon, I had a talk with Guido about how to go about doing 
this. However, I don't speak much C, so the details escape me. Jim also 
had a suggestion about this, and again, I didn't understand the details :-)


> Most of it is done already, I just need to know the right way to 
> put it together (whether the right thing to do is to enhance the 
> current Wrapper type or whether there is still a reason to have 
> a separate MethodWrapper type).

I don't see any reason to keep the method wrapper type separate from the 
base context-wrapper type. Although, it has been useful to have 
SimpleMethodWrapper in python during development, as its implementation 
has changed a number of times as we've found that we needed slightly 
different behaviour from context wrappers.

One other thing to look out for is that if a context wrapper knows that 
the descriptor being accessed is not supposed to receive a wrapped self, 
it can return directly getattr(obj, name) rather than 
Wrapper.__getattribute__(self, name). (See the last line of 
SimpleMethodWrapper.__getattribute__.) This makes accessing standard 
attributes faster for objects that have a lot of context, and thus are 
wrapped by many layers of context wrappers.

--
Steve Alexander