[Python-Dev] RE: Python-Dev digest, Vol 1 #1324 - 16 msgs

Thomas Heller thomas.heller@ion-tof.com
Mon, 23 Apr 2001 20:27:10 +0200


> "Thomas Heller" <thomas.heller@ion-tof.com> wrote,
> > Donald Beaudry's objectmodule uses the metaclass hook to provide
> > class methods. I like the resulting syntax very much:
> 
> Thank you.  I like it too, especially because MyClass.__class__
> returns what *I* would expect ;) and the source reflects that too.
> 
> > If I understand correctly (objectmodule does not run under 1.5.2 or
> > later), an instance of __class__ will become the metaclass of
> > Object, and __class__'s methods will become class methods of Object.
> 
> That's correct.  I currently use objectmodule on 1.5.2.  I would not
> be surprised if it doesnt work on newer versions though as I have
> never tried it there.  Perhaps you found an out-of-date version, or
> perhaps I never sent out a newer version.  Regardless, I'd be happy to
> get you a version that works with 1.5.2 (or upload one somewhere for
> more public consumption)

Sure I would be interested: Please send it.
Thanks for the description, I've (eagerly) read everything I found
in objectmodule-0.9.tar.gz - except I found that it would be easier
to step in a debugger through the c-code, which turned out to fail.

BTW: I just exchanged a couple of emails with Just van Rossum,
who had something very similar to yours (but you may know this already).
He pointed me to some discussions in '98 in the types-sig archives.

He proposed an additional hook in ceval.c (which would probably break
objectmodule). I've attached his proposed patch below.

Thomas

+       /*      __BEGIN__ of Just's Hook
+
+               Guido's metahook is defined as follows:
+                       - if one of the bases has a __class__ attribute (but is
+                         itself not a class!), call that thing with (name,
+                         bases, methods)
+               In addition I propose almost the opposite:
+                       - if the "methods" dict (__dict__ from the Python
+                         perspective) has a __class__ key, call that thing with
+                         (name, bases, methods)
+
+               This means that metaclasses are not special anymore, and
+               you have to specify a metaclass *explicitly* to get meta
+               behaviour. Example:
+
+                       class Foo:
+                               __class__ = MyMetaClass
+
+               as apposed to
+
+                       MyMeta = MyMetaClass("MyMeta", (), {})
+
+                       class Foo(MyMeta): pass
+
+               as it is with Guido's hook.
+
+               Reasons for this new hook:
+                       - Guido's hook abuses inheritance syntax, making it
+                         impossible to inherit from metaclasses without special
+                         trickery.
+                       - implementing Meta stuff seems cleaner. Or maybe it's
+                         just me...
+
+               At first I thought Guido's hook would not be compatible with
+               mine, but they work together beautifully: inheritance works
+               just like you would expect.
+       */
+       {
+               PyObject *callable = NULL;
+               callable = PyDict_GetItemString(methods, "__class__");
+               if (callable) {
+                       PyObject *args;
+                       PyObject *newclass = NULL;
+                       PyDict_DelItemString(methods, "__class__");
+                       args = Py_BuildValue(
+                               "(OOO)", name, bases, methods);
+                       if (args != NULL) {
+                               newclass = PyEval_CallObject(
+                                       callable, args);
+                               Py_DECREF(args);
+                       }
+                       return newclass;
+               } else {
+                       PyErr_Clear();
+               }
+       }
+       /*      __END__ of Just's Hook */
        n = PyTuple_Size(bases);
        for (i = 0; i < n; i++) {
                PyObject *base = PyTuple_GET_ITEM(bases, i);
                if (!PyClass_Check(base)) {
                        /* Call the base's *type*, if it is callable.