Skip to content

Instantly share code, notes, and snippets.

@florentx
Created February 6, 2016 17:57
Show Gist options
  • Save florentx/52dc3d00feb513d10838 to your computer and use it in GitHub Desktop.
Save florentx/52dc3d00feb513d10838 to your computer and use it in GitHub Desktop.
Finalizer objects for Python 2 and Python <= 3.3
"""Backport weakref.finalize from Python 3.5, simplified."""
import atexit
import sys
import weakref
class finalize(object):
"""Class for finalization of weakrefable objects
finalize(obj, func, *args, **kwargs) returns a callable finalizer
object which will be called when obj is garbage collected. The
first time the finalizer is called it evaluates func(*arg, **kwargs)
and returns the result. After this the finalizer is dead, and
calling it just returns None.
When the program exits any remaining finalizers will be run.
"""
# Finalizer objects don't have any state of their own.
# This ensures that they cannot be part of a ref-cycle.
__slots__ = ()
_registry = {}
def __init__(self, obj, func, *args, **kwargs):
info = functools.partial(func, *args, **kwargs)
info.weakref = weakref.ref(obj, self)
self._registry[self] = info
def __call__(self, wr):
"""Return func(*args, **kwargs) if alive"""
info = self._registry.pop(self, None)
if info:
return info()
@classmethod
def _exitfunc(cls):
if not cls._registry:
return
for finalizer in list(cls._registry)
try:
finalizer(None)
except Exception:
sys.excepthook(*sys.exc_info())
assert finalizer not in cls._registry
atexit.register(finalize._exitfunc)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment