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

This commit is contained in:
Wirawan Purwanto
2015-03-16 18:07:18 -04:00
parent 1c5ec91b64
commit 7568f5874e
2 changed files with 94 additions and 1 deletions

View File

@@ -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: