summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2001-10-29 22:11:00 (GMT)
committerGuido van Rossum <guido@python.org>2001-10-29 22:11:00 (GMT)
commit7ad2d1eb8eaf8db634b440ef3c4f5a1b9b654cb5 (patch)
treeceb93389ae63c9e74452ceeda94a32c046d1cea2 /Objects
parentc57a285cb4cd61439fd3ea804184ed8a8a1ac358 (diff)
downloadcpython-7ad2d1eb8eaf8db634b440ef3c4f5a1b9b654cb5.zip
cpython-7ad2d1eb8eaf8db634b440ef3c4f5a1b9b654cb5.tar.gz
cpython-7ad2d1eb8eaf8db634b440ef3c4f5a1b9b654cb5.tar.bz2
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.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/typeobject.c74
1 files changed, 74 insertions, 0 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index d5f6a8f..b7abba9 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -230,6 +230,77 @@ subtype_traverse(PyObject *self, visitproc visit, void *arg)
return 0;
}
+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,6 +309,9 @@ subtype_dealloc(PyObject *self)
/* This exists so we can DECREF self->ob_type */
+ if (call_finalizer(self) < 0)
+ return;
+
/* Find the nearest base with a different tp_dealloc */
type = self->ob_type;
base = type->tp_base;