[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