* Added a tool to create bound instance method with weak ref to the instance.
This commit is contained in:
@@ -10,10 +10,30 @@
|
|||||||
import sys
|
import sys
|
||||||
import new
|
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):
|
def make_unbound_instance_method(method):
|
||||||
"""Generates an unbound instance method from a possibly bound
|
"""Generates an unbound instance method from a possibly bound
|
||||||
instance method."""
|
instance method.
|
||||||
|
"""
|
||||||
return new.instancemethod(method.im_func, None, method.im_class)
|
return new.instancemethod(method.im_func, None, method.im_class)
|
||||||
|
|
||||||
|
|
||||||
@@ -32,6 +52,41 @@ def make_unbound_method(method):
|
|||||||
return 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):
|
def function_name(f):
|
||||||
"""Returns the given name of a function (or callable object)."""
|
"""Returns the given name of a function (or callable object)."""
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -15,6 +15,13 @@ wpylib.py.im_weakref
|
|||||||
Complement of weakref's weak reference for an instance method
|
Complement of weakref's weak reference for an instance method
|
||||||
(whether bound or unbound).
|
(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
|
Original-source: Linux Screen Reader project
|
||||||
Copied-from: http://mindtrove.info/python-weak-references/
|
Copied-from: http://mindtrove.info/python-weak-references/
|
||||||
Date: 20110607
|
Date: 20110607
|
||||||
@@ -84,3 +91,34 @@ class im_ref(object):
|
|||||||
Inverse of __eq__.
|
Inverse of __eq__.
|
||||||
'''
|
'''
|
||||||
return not self.__eq__(other)
|
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)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user