[Python-ideas] Weak-referencing/weak-proxying of (bound) methods

Jan Kaliszewski zuo at chopin.edu.pl
Sat Jun 16 01:41:50 CEST 2012


Tal Einat dixit (2012-06-15, 15:41):

> On Mon, Jun 11, 2012 at 2:16 AM, Jan Kaliszewski <zuo at chopin.edu.pl> wrote:
[snip]
> >    >>> import weakref
> >    >>> class A:
> >    ...     def method(self): print(self)
> >    ...
> >    >>> A.method
> >    <function method at 0xb732926c>
> >    >>> a = A()
> >    >>> a.method
> >    <bound method A.method of <__main__.A object at 0xb7326bec>>
> >    >>> r = weakref.ref(a.method)  # creating a weak reference
> >    >>> r                          # ...but it appears to be dead
> >    <weakref at 0xb7327d9c; dead>
> >    >>> w = weakref.proxy(a.method)  # the same with a weak proxy
> >    >>> w
> >    <weakproxy at 0xb7327d74 to NoneType at 0x829f7d0>
> >    >>> w()
> >    Traceback (most recent call last):
> >      File "<stdin>", line 1, in <module>
> >    ReferenceError: weakly-referenced object no longer exists
> >
> > This behaviour is perfectly correct -- but still surprising,
> > especially for people who know little about method creation
> > machinery, descriptors etc.
> >
> > I think it would be nice to make this 'trap' less painful --
[snip]
> > A prototype implementation:
> >
> >    class InstanceCachedMethod(object):
> >
> >        def __init__(self, func):
> >            self.func = func
> >            (self.instance_attr_name
> >            ) = '__{0}_method_ref'.format(func.__name__)
> >
> >        def __get__(self, instance, owner):
> >            if instance is None:
> >                return self.func
> >            try:
> >                return getattr(instance, self.instance_attr_name)
> >            except AttributeError:
> >                method = types.MethodType(self.func, instance)
> >                setattr(instance, self.instance_attr_name, method)
> >                return method
[snip]
> I was bitten by this issue a while ago as well. It made working with
> weakref proxies much more involved than I expected it would be.
> 
> Wouldn't it be better to approach the issue from the opposite end, and
> improve/wrap/replace weakref.proxy with something that can handle bound
> methods?

Indeed, probably could it be done by wrapping weakref.ref()/proxy()
with something like the following:

    # here `obj` is the object that is being weak-referenced...
    if isinstance(obj, types.MethodType):
        try:
            cache = obj.__self__.__method_cache__
        except AttributeError:
            cache = obj.__self__.__method_cache__ = WeakKeyDictionary()
        method_cache.setdefault(obj.__func__, set()).add(obj)

(Using WeakKeyDictionary with corresponding function objects as weak
keys -- to provide automagic cleanup when a function is deleted, e.g.
replaced with another one.  In other words: the actual weak ref/proxy
to a method lives as long as the corresponding function does).

Any thoughts?

Cheers.
*j




More information about the Python-ideas mailing list