''' Modified C-level finalizer by Benjamin Peterson Available at http://code.activestate.com/recipes/577242-calling-c-level-finalizers-without-__del__/ ''' import sys import traceback import weakref class OwnerRef(weakref.ref): """A simple weakref.ref subclass, so attributes can be added.""" pass def _run_finalizer(ref): """Internal weakref callback to run finalizers""" del _finalize_refs[ref.owner] for item, finalizer in ref.items: try: finalizer(item) except Exception: print>>sys.stderr, "Exception running {}:".format(finalizer) traceback.print_exc() _finalize_refs = {} def track(owner, item, finalizer): """Register an object for finalization. ``owner`` is the the object which is responsible for ``item``. ``finalizer`` will be called with ``item`` as its only argument when ``owner`` is destroyed by the garbage collector. """ if id(owner) in _finalize_refs: ref = _finalize_refs[id(owner)] else: ref = OwnerRef(owner, _run_finalizer) ref.owner = id(owner) ref.items = [] ref.items.append((item, finalizer)) _finalize_refs[id(owner)] = ref def untrack(owner, item): ref = _finalize_refs[id(owner)] # search and remove the item from the ref for i, (item_i, _) in enumerate(ref.items): if item_i is item: del ref.items[i] # remove the ref if it is empty if not ref.items: del _finalize_refs[id(owner)] class OwnerMixin(object): def _finalizer_track(self, item): if not hasattr(self, '_finalize'): raise AttributeError("%s must define a _finalize method" % self) track(self, item, type(self)._finalize) def _finalizer_untrack(self, item): untrack(self, item)