summaryrefslogtreecommitdiffstats
path: root/Python/ceval.c
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1997-07-31 03:54:02 (GMT)
committerGuido van Rossum <guido@python.org>1997-07-31 03:54:02 (GMT)
commit55b9ab5bdb0ef3b00339d751a8db5e23aa936cf0 (patch)
treeca863911a7ea4619c2a97c58c524a1882a040f23 /Python/ceval.c
parentfd16ca4542b418e5fa1f70782f65f905540da711 (diff)
downloadcpython-55b9ab5bdb0ef3b00339d751a8db5e23aa936cf0.zip
cpython-55b9ab5bdb0ef3b00339d751a8db5e23aa936cf0.tar.gz
cpython-55b9ab5bdb0ef3b00339d751a8db5e23aa936cf0.tar.bz2
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!
Diffstat (limited to 'Python/ceval.c')
-rw-r--r--Python/ceval.c37
1 files changed, 27 insertions, 10 deletions
diff --git a/Python/ceval.c b/Python/ceval.c
index ec2e419..205d8d4 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -2689,22 +2689,39 @@ build_class(methods, bases, name)
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");