[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