diff Python/ceval.c @ 5911:6986781a07ef legacy-trunk

Extend the "Don Beaudry hack" with "Guido's corollary" -- if the base class has a __class__ attribute, call that to create the new class. This allows us to write metaclasses purely in C!
author Guido van Rossum <guido@python.org>
date Thu, 31 Jul 1997 03:54:02 +0000
parents 9841bce37c4d
children 8d2194e22e67
line wrap: on
line diff
--- a/Python/ceval.c	Wed Jul 30 22:05:07 1997 +0000
+++ b/Python/ceval.c	Thu Jul 31 03:54:02 1997 +0000
@@ -2689,22 +2689,39 @@
 		return NULL;
 	}
 	for (i = PyTuple_Size(bases); --i >= 0; ) {
+		/* XXX Is it intentional that the *last* base gets a
+		   chance at this first? */
 		PyObject *base = PyTuple_GET_ITEM(bases, i);
 		if (!PyClass_Check(base)) {
 			/* Call the base's *type*, if it is callable.
 			   This code is a hook for Donald Beaudry's
 			   and Jim Fulton's type extensions.  In
 			   unexended Python it will never be triggered
-			   since its types are not callable. */
-			if (base->ob_type->ob_type->tp_call) {
-			  	PyObject *args;
-				PyObject *class;
-				args = Py_BuildValue("(OOO)",
-						     name, bases, methods);
-				class = PyEval_CallObject(
-					(PyObject *)base->ob_type, args);
-				Py_DECREF(args);
-				return class;
+			   since its types are not callable.
+			   Ditto: call the bases's *class*, if it has
+			   one.  This makes the same thing possible
+			   without writing C code.  A true meta-object
+			   protocol! */
+			PyObject *basetype = (PyObject *)base->ob_type;
+			PyObject *callable = NULL;
+			if (PyCallable_Check(basetype))
+				callable = basetype;
+			else
+				callable = PyObject_GetAttrString(
+					base, "__class__");
+			if (callable) {
+				PyObject *args;
+				PyObject *newclass = NULL;
+				args = Py_BuildValue(
+					"(OOO)", name, bases, methods);
+				if (args != NULL) {
+					newclass = PyEval_CallObject(
+						callable, args);
+					Py_DECREF(args);
+				}
+				if (callable != basetype)
+					Py_DECREF(callable);
+				return newclass;
 			}
 			PyErr_SetString(PyExc_TypeError,
 				"base is not a class object");