[Python-checkins] CVS: python/dist/src/Objects typeobject.c,2.21,2.22
Guido van Rossum
gvanrossum@users.sourceforge.net
Tue, 07 Aug 2001 09:40:59 -0700
Update of /cvsroot/python/python/dist/src/Objects
In directory usw-pr-cvs1:/tmp/cvs-serv899
Modified Files:
typeobject.c
Log Message:
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.
Index: typeobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/typeobject.c,v
retrieving revision 2.21
retrieving revision 2.22
diff -C2 -d -r2.21 -r2.22
*** typeobject.c 2001/08/06 16:50:37 2.21
--- typeobject.c 2001/08/07 16:40:56 2.22
***************
*** 448,451 ****
--- 448,452 ----
staticforward void object_dealloc(PyObject *);
staticforward int object_init(PyObject *, PyObject *, PyObject *);
+ staticforward int add_tp_new_wrapper(PyTypeObject *);
static PyObject *
***************
*** 663,666 ****
--- 664,678 ----
/* 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;
}
***************
*** 894,898 ****
object_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
! PyType_GenericNew, /* tp_new */
object_free, /* tp_free */
};
--- 906,910 ----
object_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
! 0, /* tp_new */
object_free, /* tp_free */
};
***************
*** 921,936 ****
static int
! add_wrappers(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
{
PyObject *dict = type->tp_defined;
! for (; base->name != NULL; base++) {
PyObject *descr;
! if (PyDict_GetItemString(dict, base->name))
continue;
! descr = PyDescr_NewWrapper(type, base, wrapped);
if (descr == NULL)
return -1;
! if (PyDict_SetItemString(dict, base->name, descr) < 0)
return -1;
Py_DECREF(descr);
--- 933,948 ----
static int
! add_wrappers(PyTypeObject *type, struct wrapperbase *wraps, void *wrapped)
{
PyObject *dict = type->tp_defined;
! for (; wraps->name != NULL; wraps++) {
PyObject *descr;
! if (PyDict_GetItemString(dict, wraps->name))
continue;
! descr = PyDescr_NewWrapper(type, wraps, wrapped);
if (descr == NULL)
return -1;
! if (PyDict_SetItemString(dict, wraps->name, descr) < 0)
return -1;
Py_DECREF(descr);
***************
*** 1871,1876 ****
add_tp_new_wrapper(PyTypeObject *type)
{
! PyObject *func = PyCFunction_New(tp_new_methoddef, (PyObject *)type);
if (func == NULL)
return -1;
--- 1883,1891 ----
add_tp_new_wrapper(PyTypeObject *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;
***************
*** 1878,1881 ****
--- 1893,1917 ----
}
+ /* 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)
***************
*** 1967,1977 ****
ADD(type->tp_init, tab_init);
! if (type->tp_new != NULL)
! add_tp_new_wrapper(type);
return 0;
}
! /* Slot wrappers that call the corresponding __foo__ slot */
#define SLOT0(SLOTNAME, OPNAME) \
--- 2003,2016 ----
ADD(type->tp_init, tab_init);
! if (type->tp_new != NULL) {
! if (add_tp_new_wrapper(type) < 0)
! return -1;
! }
return 0;
}
! /* Slot wrappers that call the corresponding __foo__ slot. See comments
! below at override_slots() for more explanation. */
#define SLOT0(SLOTNAME, OPNAME) \
***************
*** 2295,2298 ****
--- 2334,2353 ----
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