* Added a tool to create bound instance method with weak ref to the instance.

master
Wirawan Purwanto 10 years ago
parent 1c5ec91b64
commit 7568f5874e
  1. 57
      py/__init__.py
  2. 38
      py/im_weakref.py

@ -10,10 +10,30 @@
import sys
import new
"""
wpylib.py module
Collection of low-level pythonic hacks
Instance method hacks
---------------------
make_unbound_instance_method::
make_unbound_method::
One possible reason of using these routines is to provide an
alterable calling point with different implementations--somewhat like
virtual methods, but something that can be changed dynamically
on-the-fly.
NOTE: The trick provided by wpylib.py.im_ref.im_ref class is
a better way to accomplish the same thing.
"""
def make_unbound_instance_method(method):
"""Generates an unbound instance method from a possibly bound
instance method."""
instance method.
"""
return new.instancemethod(method.im_func, None, method.im_class)
@ -32,6 +52,41 @@ def make_unbound_method(method):
return method
def make_weakly_bound_method(method, instance):
"""Creates a bound instance method, where the instance is weakly
referred.
This trick is necessary if the bound method is to be attached
to that instance's attribute list (e.g. via instance.__dict__),
because otherwise a circular reference occurs:
bound_method -> instance -> bound_method (via __dict__)
CAVEAT: Know what you are doing! In general, this is a haram trick.
We circumvent the standard class type-safety mechanism in python here:
if the `method` actually belongs to a completely unrelated class,
this routine still accepts it and allow the function to be called.
"""
# NOTE: This is an identical trick to wpylib.py.im_ref.xbound_im_ref;
# the latter (the OO interface) is better because
# it does not need function closure, and that the object data is
# easier to diagnose.
from weakref import ref
instance_ref = ref(instance)
instance_cls = instance.__class__
try:
im_func, im_class = method.im_func, method.im_class
#im_method = new.instancemethod(im_func, None, instance_cls)
except AttributeError:
im_func = method
# Assume this is a function defined outside a class, which is then
# injected into this instance.
# The first argument must be the usual `self` argument.
return lambda *args, **kwargs: method(instance_ref(), *args, **kwargs)
return lambda *args, **kwargs: im_func(instance_ref(), *args, **kwargs)
def function_name(f):
"""Returns the given name of a function (or callable object)."""
try:

@ -15,6 +15,13 @@ wpylib.py.im_weakref
Complement of weakref's weak reference for an instance method
(whether bound or unbound).
This trick is necessary if the bound instance method is to be attached
to that instance's attribute list (e.g. on `instance.__dict__`),
because otherwise a circular reference occurs:
bound_method -> instance -> bound_method (via __dict__)
Original-source: Linux Screen Reader project
Copied-from: http://mindtrove.info/python-weak-references/
Date: 20110607
@ -84,3 +91,34 @@ class im_ref(object):
Inverse of __eq__.
'''
return not self.__eq__(other)
class xbound_im_ref(im_ref):
'''A dirty hack to make an im_ref object where the callable can be
an instance method belonging to a completely different class, or
to an ordinary function.
CAUTION: Know what you are doing! In general, this is a haram trick.
This object is used for forced injection of an external method as
a class method.
We circumvent the standard class type-safety mechanism in python here:
if the `method` actually belongs to a completely unrelated class,
this routine still accepts it and allow the function to be called.
'''
def __init__(self, method, instance):
self.inst = weakref.ref(instance)
self.klass = instance.__class__
try:
self.func, im_class = method.im_func, method.im_class
except AttributeError:
# Assume this is a function defined outside a class, which is then
# injected into this instance.
# The first argument must be the usual `self` argument.
self.func = method
def __call__(self, *args, **kwargs):
if self.inst is not None and self.inst() is None:
raise ReferenceError, "Original object (of type %s) is already dead." % (self.klass)
return self.func(self.inst(), *args, **kwargs)

Loading…
Cancel
Save