[Python-checkins] CVS: python/dist/src/Objects typeobject.c,2.115,2.116

Guido van Rossum gvanrossum@users.sourceforge.net
Mon, 29 Oct 2001 14:09:39 -0800


Update of /cvsroot/python/python/dist/src/Objects
In directory usw-pr-cvs1:/tmp/cvs-serv22912

Modified Files:
	typeobject.c 
Log Message:
Add __del__ callbacks.  They are too useful to leave out.

XXX Remaining problems:

- The GC module doesn't know about these; I think it has its reasons
  to disallow calling __del__, but for now, __del__ on new-style
  objects is called when the GC module discards an object, for better
  or for worse.

- The code to call a __del__ handler is really ridiculously
  complicated, due to all the different debug #ifdefs.  I've copied
  this from the similar code in classobject.c, so I'm pretty sure I
  did it right, but it's not pretty. :-(

- No tests yet.


Index: typeobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/typeobject.c,v
retrieving revision 2.115
retrieving revision 2.116
diff -C2 -d -r2.115 -r2.116
*** typeobject.c	2001/10/29 14:33:44	2.115
--- typeobject.c	2001/10/29 22:09:37	2.116
***************
*** 231,234 ****
--- 231,305 ----
  }
  
+ staticforward PyObject *lookup_maybe(PyObject *, char *, PyObject **);
+ 
+ static int
+ call_finalizer(PyObject *self)
+ {
+ 	static PyObject *del_str = NULL;
+ 	PyObject *del, *res;
+ 	PyObject *error_type, *error_value, *error_traceback;
+ 
+ 	/* Temporarily resurrect the object. */
+ #ifdef Py_TRACE_REFS
+ #ifndef Py_REF_DEBUG
+ #   error "Py_TRACE_REFS defined but Py_REF_DEBUG not."
+ #endif
+ 	/* much too complicated if Py_TRACE_REFS defined */
+ 	_Py_NewReference((PyObject *)self);
+ #ifdef COUNT_ALLOCS
+ 	/* compensate for boost in _Py_NewReference; note that
+ 	 * _Py_RefTotal was also boosted; we'll knock that down later.
+ 	 */
+ 	self->ob_type->tp_allocs--;
+ #endif
+ #else /* !Py_TRACE_REFS */
+ 	/* Py_INCREF boosts _Py_RefTotal if Py_REF_DEBUG is defined */
+ 	Py_INCREF(self);
+ #endif /* !Py_TRACE_REFS */
+ 
+ 	/* Save the current exception, if any. */
+ 	PyErr_Fetch(&error_type, &error_value, &error_traceback);
+ 
+ 	/* Execute __del__ method, if any. */
+ 	del = lookup_maybe(self, "__del__", &del_str);
+ 	if (del != NULL) {
+ 		res = PyEval_CallObject(del, NULL);
+ 		if (res == NULL)
+ 			PyErr_WriteUnraisable(del);
+ 		else
+ 			Py_DECREF(res);
+ 		Py_DECREF(del);
+ 	}
+ 
+ 	/* Restore the saved exception. */
+ 	PyErr_Restore(error_type, error_value, error_traceback);
+ 
+ 	/* Undo the temporary resurrection; can't use DECREF here, it would
+ 	 * cause a recursive call.
+ 	 */
+ #ifdef Py_REF_DEBUG
+ 	/* _Py_RefTotal was boosted either by _Py_NewReference or
+ 	 * Py_INCREF above.
+ 	 */
+ 	_Py_RefTotal--;
+ #endif
+ 	if (--self->ob_refcnt > 0) {
+ #ifdef COUNT_ALLOCS
+ 		self->ob_type->tp_frees--;
+ #endif
+ 		_PyObject_GC_TRACK(self);
+ 		return -1; /* __del__ added a reference; don't delete now */
+ 	}
+ #ifdef Py_TRACE_REFS
+ 	_Py_ForgetReference((PyObject *)self);
+ #ifdef COUNT_ALLOCS
+ 	/* compensate for increment in _Py_ForgetReference */
+ 	self->ob_type->tp_frees--;
+ #endif
+ #endif
+ 
+ 	return 0;
+ }
+ 
  static void
  subtype_dealloc(PyObject *self)
***************
*** 238,241 ****
--- 309,315 ----
  
  	/* This exists so we can DECREF self->ob_type */
+ 
+ 	if (call_finalizer(self) < 0)
+ 		return;
  
  	/* Find the nearest base with a different tp_dealloc */