mirror of https://github.com/python/cpython
Cosmetics:
- Add comment blocks explaining add_operators() and override_slots(). (This file could use some more explaining, but this is all I had breath for today. :) - Renamed the argument 'base' of add_wrappers() to 'wraps' because it's not a base class (which is what the 'base' identifier is used for elsewhere). Small nits: - Fix add_tp_new_wrapper() to avoid overwriting an existing __new__ descriptor in tp_defined. - In add_operators(), check the return value of add_tp_new_wrapper(). Functional change: - Remove the tp_new functionality from PyBaseObject_Type; this means you can no longer instantiate the 'object' type. It's only useful as a base class. - To make up for the above loss, add tp_new to dynamic types. This has to be done in a hackish way (after override_slots() has been called, with an explicit call to add_tp_new_wrapper() at the very end) because otherwise I ran into recursive calls of slot_tp_new(). Sigh.
This commit is contained in:
parent
cd738364ce
commit
f040ede6e8
|
@ -447,6 +447,7 @@ solid_base(PyTypeObject *type)
|
|||
|
||||
staticforward void object_dealloc(PyObject *);
|
||||
staticforward int object_init(PyObject *, PyObject *, PyObject *);
|
||||
staticforward int add_tp_new_wrapper(PyTypeObject *);
|
||||
|
||||
static PyObject *
|
||||
type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
|
||||
|
@ -662,6 +663,17 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
|
|||
|
||||
/* Override slots that deserve it */
|
||||
override_slots(type, type->tp_defined);
|
||||
|
||||
/* Special hack for __new__ */
|
||||
if (type->tp_new == NULL) {
|
||||
/* Can't do this earlier, or some nasty recursion happens. */
|
||||
type->tp_new = PyType_GenericNew;
|
||||
if (add_tp_new_wrapper(type) < 0) {
|
||||
Py_DECREF(type);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return (PyObject *)type;
|
||||
}
|
||||
|
||||
|
@ -893,7 +905,7 @@ PyTypeObject PyBaseObject_Type = {
|
|||
0, /* tp_dictoffset */
|
||||
object_init, /* tp_init */
|
||||
PyType_GenericAlloc, /* tp_alloc */
|
||||
PyType_GenericNew, /* tp_new */
|
||||
0, /* tp_new */
|
||||
object_free, /* tp_free */
|
||||
};
|
||||
|
||||
|
@ -920,18 +932,18 @@ add_methods(PyTypeObject *type, PyMethodDef *meth)
|
|||
}
|
||||
|
||||
static int
|
||||
add_wrappers(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
|
||||
add_wrappers(PyTypeObject *type, struct wrapperbase *wraps, void *wrapped)
|
||||
{
|
||||
PyObject *dict = type->tp_defined;
|
||||
|
||||
for (; base->name != NULL; base++) {
|
||||
for (; wraps->name != NULL; wraps++) {
|
||||
PyObject *descr;
|
||||
if (PyDict_GetItemString(dict, base->name))
|
||||
if (PyDict_GetItemString(dict, wraps->name))
|
||||
continue;
|
||||
descr = PyDescr_NewWrapper(type, base, wrapped);
|
||||
descr = PyDescr_NewWrapper(type, wraps, wrapped);
|
||||
if (descr == NULL)
|
||||
return -1;
|
||||
if (PyDict_SetItemString(dict, base->name, descr) < 0)
|
||||
if (PyDict_SetItemString(dict, wraps->name, descr) < 0)
|
||||
return -1;
|
||||
Py_DECREF(descr);
|
||||
}
|
||||
|
@ -1870,13 +1882,37 @@ static struct PyMethodDef tp_new_methoddef[] = {
|
|||
static int
|
||||
add_tp_new_wrapper(PyTypeObject *type)
|
||||
{
|
||||
PyObject *func = PyCFunction_New(tp_new_methoddef, (PyObject *)type);
|
||||
PyObject *func;
|
||||
|
||||
if (PyDict_GetItemString(type->tp_defined, "__new__") != NULL)
|
||||
return 0;
|
||||
func = PyCFunction_New(tp_new_methoddef, (PyObject *)type);
|
||||
if (func == NULL)
|
||||
return -1;
|
||||
return PyDict_SetItemString(type->tp_defined, "__new__", func);
|
||||
}
|
||||
|
||||
/* This function is called by PyType_InitDict() to populate the type's
|
||||
dictionary with method descriptors for function slots. For each
|
||||
function slot (like tp_repr) that's defined in the type, one or
|
||||
more corresponding descriptors are added in the type's tp_defined
|
||||
dictionary under the appropriate name (like __repr__). Some
|
||||
function slots cause more than one descriptor to be added (for
|
||||
example, the nb_add slot adds both __add__ and __radd__
|
||||
descriptors) and some function slots compete for the same
|
||||
descriptor (for example both sq_item and mp_subscript generate a
|
||||
__getitem__ descriptor). This only adds new descriptors and
|
||||
doesn't overwrite entries in tp_defined that were previously
|
||||
defined. The descriptors contain a reference to the C function
|
||||
they must call, so that it's safe if they are copied into a
|
||||
subtype's __dict__ and the subtype has a different C function in
|
||||
its slot -- calling the method defined by the descriptor will call
|
||||
the C function that was used to create it, rather than the C
|
||||
function present in the slot when it is called. (This is important
|
||||
because a subtype may have a C function in the slot that calls the
|
||||
method from the dictionary, and we want to avoid infinite recursion
|
||||
here.) */
|
||||
|
||||
static int
|
||||
add_operators(PyTypeObject *type)
|
||||
{
|
||||
|
@ -1966,13 +2002,16 @@ add_operators(PyTypeObject *type)
|
|||
ADD(type->tp_descr_set, tab_descr_set);
|
||||
ADD(type->tp_init, tab_init);
|
||||
|
||||
if (type->tp_new != NULL)
|
||||
add_tp_new_wrapper(type);
|
||||
if (type->tp_new != NULL) {
|
||||
if (add_tp_new_wrapper(type) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Slot wrappers that call the corresponding __foo__ slot */
|
||||
/* Slot wrappers that call the corresponding __foo__ slot. See comments
|
||||
below at override_slots() for more explanation. */
|
||||
|
||||
#define SLOT0(SLOTNAME, OPNAME) \
|
||||
static PyObject * \
|
||||
|
@ -2295,6 +2334,22 @@ slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
return x;
|
||||
}
|
||||
|
||||
/* This is called at the very end of type_new() (even after
|
||||
PyType_InitDict()) to complete the initialization of dynamic types.
|
||||
The dict argument is the dictionary argument passed to type_new(),
|
||||
which is the local namespace of the class statement, in other
|
||||
words, it contains the methods. For each special method (like
|
||||
__repr__) defined in the dictionary, the corresponding function
|
||||
slot in the type object (like tp_repr) is set to a special function
|
||||
whose name is 'slot_' followed by the slot name and whose signature
|
||||
is whatever is required for that slot. These slot functions look
|
||||
up the corresponding method in the type's dictionary and call it.
|
||||
The slot functions have to take care of the various peculiarities
|
||||
of the mapping between slots and special methods, such as mapping
|
||||
one slot to multiple methods (tp_richcompare <--> __le__, __lt__
|
||||
etc.) or mapping multiple slots to a single method (sq_item,
|
||||
mp_subscript <--> __getitem__). */
|
||||
|
||||
static void
|
||||
override_slots(PyTypeObject *type, PyObject *dict)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue