New submission from Sundance <sunda...@ierne.eu.org>:

SUMMARY
=======

The behavior of instance methods makes it impossible to keep a weakref on them. 
The reference dies instantly even if the instance and the method still exist.


EXAMPLE
=======

>>> import weakref

>>> callbacks = weakref.WeakSet()

>>> def callback1():
...   print "In callback1."

>>> class SomeClass:
...   def callback2(self):
...     print "In callback2."

>>> some_instance = SomeClass()

>>> callbacks.add( callback1 )
>>> callbacks.add( some_instance.callback2 )

>>> for callback in callbacks:
...   callback()
In callback1.

>>> ## callback2 is never called!


ANALYSIS
========

The WeakSet in the example above, and the weakref.ref() it employs, actually 
behave as specified. It's the particular nature of bound methods that causes 
the unexpected behavior.

>From what I understand, instance methods are bound dynamically when looked up 
>on the instance. A new object of type instancemethod is created each time:

>>> t1 = some_instance.callback
>>> t2 = some_instance.callback
>>> t1 is t2
False

So when a program calls weakref.ref(some_instance.callback), a new 
instancemethod object is created on the fly, a weakref to that object is 
created... and the instancemethod object dies, because its refcount is 0.

This fundamental difference between instance methods and other callables makes 
it painful to implement weakly referencing callback registries.


PROPOSED SOLUTION
=================

Changing the fundamental nature of instance methods to accommodate one single 
corner case doesn't seem worthwhile.

Similarly, changing the behavior of weakref.ref(), which does work as 
specified, is probably not a good idea.

My approach is thus to provide a new helper, WeakCallableRef, that behaves like 
weakref.ref(), but is safe to use on callables and does what you would 
naturally expect with instance methods.

It works by binding the lifetime of the ref to that of 1/ the instance bearing 
the method, and 2/ the unbound method itself. It is also safe to use on other 
function types beside instance methods, so implementations of callback 
registries don't have to special case depending on the callable type.

The unexpected behavior should also be mentioned somewhere in the weakref 
documentation, by the way.

See attached file for a proposed implementation.

----------
components: Library (Lib)
files: WeakCallableRef.py
messages: 158828
nosy: Sundance
priority: normal
severity: normal
status: open
title: Instance methods and WeakRefs don't mix.
type: behavior
versions: Python 2.7
Added file: http://bugs.python.org/file25288/WeakCallableRef.py

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue14631>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to