summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2001-08-07 16:40:56 (GMT)
committerGuido van Rossum <guido@python.org>2001-08-07 16:40:56 (GMT)
commitf040ede6e8a0ccb37f60798ad1cc48d265b5d2c2 (patch)
treece6f3b4d10773f2879fd395e736f500eafbf87fd /Objects
parentcd738364ce1a5de26a891b61d2c1baf1e692f0e0 (diff)
downloadcpython-f040ede6e8a0ccb37f60798ad1cc48d265b5d2c2.zip
cpython-f040ede6e8a0ccb37f60798ad1cc48d265b5d2c2.tar.gz
cpython-f040ede6e8a0ccb37f60798ad1cc48d265b5d2c2.tar.bz2
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.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/typeobject.c75
1 files changed, 65 insertions, 10 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 37afb47..5d3255a 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -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)
{