diff Python/ceval.c @ 19890:31fe8b3e276b legacy-trunk

build_class(): one more (hopefully the last) step on the way to backwards compatibility. When using the class of the first base as the metaclass, use its __class__ attribute in preference over its ob_type slot. This ensures that we can still use classic classes as metaclasse, as shown in the original "Metaclasses" essay. This also makes all the examples in Demo/metaclasses/ work again (maybe these should be turned into a test suite?).
author Guido van Rossum <guido@python.org>
date Wed, 12 Sep 2001 19:19:18 +0000
parents 04218e85b156
children 0491ea611bc4
line wrap: on
line diff
--- a/Python/ceval.c	Wed Sep 12 19:12:49 2001 +0000
+++ b/Python/ceval.c	Wed Sep 12 19:19:18 2001 +0000
@@ -3500,25 +3500,32 @@
 static PyObject *
 build_class(PyObject *methods, PyObject *bases, PyObject *name)
 {
-	PyObject *metaclass = NULL;
+	PyObject *metaclass = NULL, *result, *base;
 
 	if (PyDict_Check(methods))
 		metaclass = PyDict_GetItemString(methods, "__metaclass__");
-
-	if (metaclass == NULL) {
-		if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0)
-			metaclass = (PyObject *)
-				PyTuple_GET_ITEM(bases, 0)->ob_type;
-		else {
-			PyObject *g = PyEval_GetGlobals();
-			if (g != NULL && PyDict_Check(g))
-				metaclass = PyDict_GetItemString(
-					g, "__metaclass__");
-			if (metaclass == NULL)
-				metaclass = (PyObject *) &PyClass_Type;
+	if (metaclass != NULL)
+		Py_INCREF(methods);
+	else if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) {
+		base = PyTuple_GET_ITEM(bases, 0);
+		metaclass = PyObject_GetAttrString(base, "__class__");
+		if (metaclass == NULL) {
+			PyErr_Clear();
+			metaclass = (PyObject *)base->ob_type;
+			Py_INCREF(metaclass);
 		}
 	}
-	return PyObject_CallFunction(metaclass, "OOO", name, bases, methods);
+	else {
+		PyObject *g = PyEval_GetGlobals();
+		if (g != NULL && PyDict_Check(g))
+			metaclass = PyDict_GetItemString(g, "__metaclass__");
+		if (metaclass == NULL)
+			metaclass = (PyObject *) &PyClass_Type;
+		Py_INCREF(metaclass);
+	}
+	result = PyObject_CallFunction(metaclass, "OOO", name, bases, methods);
+	Py_DECREF(metaclass);
+	return result;
 }
 
 static int