mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
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!
This commit is contained in:
parent
fd16ca4542
commit
55b9ab5bdb
1 changed files with 27 additions and 10 deletions
|
@ -2689,22 +2689,39 @@ build_class(methods, bases, name)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
for (i = PyTuple_Size(bases); --i >= 0; ) {
|
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);
|
PyObject *base = PyTuple_GET_ITEM(bases, i);
|
||||||
if (!PyClass_Check(base)) {
|
if (!PyClass_Check(base)) {
|
||||||
/* Call the base's *type*, if it is callable.
|
/* Call the base's *type*, if it is callable.
|
||||||
This code is a hook for Donald Beaudry's
|
This code is a hook for Donald Beaudry's
|
||||||
and Jim Fulton's type extensions. In
|
and Jim Fulton's type extensions. In
|
||||||
unexended Python it will never be triggered
|
unexended Python it will never be triggered
|
||||||
since its types are not callable. */
|
since its types are not callable.
|
||||||
if (base->ob_type->ob_type->tp_call) {
|
Ditto: call the bases's *class*, if it has
|
||||||
PyObject *args;
|
one. This makes the same thing possible
|
||||||
PyObject *class;
|
without writing C code. A true meta-object
|
||||||
args = Py_BuildValue("(OOO)",
|
protocol! */
|
||||||
name, bases, methods);
|
PyObject *basetype = (PyObject *)base->ob_type;
|
||||||
class = PyEval_CallObject(
|
PyObject *callable = NULL;
|
||||||
(PyObject *)base->ob_type, args);
|
if (PyCallable_Check(basetype))
|
||||||
Py_DECREF(args);
|
callable = basetype;
|
||||||
return class;
|
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,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"base is not a class object");
|
"base is not a class object");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue