[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