On Mon, Mar 2, 2015 at 4:04 AM, Cem Karan <cfkar...@gmail.com> wrote: > On Feb 26, 2015, at 2:54 PM, Ian Kelly <ian.g.ke...@gmail.com> wrote: >> On Feb 26, 2015 4:00 AM, "Cem Karan" <cfkar...@gmail.com> wrote: >> > >> > >> > On Feb 26, 2015, at 12:36 AM, Gregory Ewing <greg.ew...@canterbury.ac.nz> >> > wrote: >> > >> > > Cem Karan wrote: >> > >> I think I see what you're talking about now. Does WeakMethod >> > >> (https://docs.python.org/3/library/weakref.html#weakref.WeakMethod) >> > >> solve >> > >> this problem? >> > > >> > > Yes, that looks like it would work. >> > >> > >> > Cool! >> >> Sometimes I wonder whether anybody reads my posts. I suggested a solution >> involving WeakMethod four days ago that additionally extends the concept to >> non-method callbacks (requiring a small amount of extra effort from the >> client in those cases, but I think that is unavoidable. There is no way that >> the framework can determine the appropriate lifetime for a closure-based >> callback.) > > I apologize about taking so long to reply to everyone's posts, but I've been > busy at home. > > Ian, it took me a while to do some research to understand WHY what you were > suggesting was important; you're right about storing the object as well as > the method/function separately, but I think that WeakMethod might solve that > completely, correct? Are there any cases where WeakMethod wouldn't work?
WeakMethod only works for bound method objects. If you pass it a non-method function, you'll get a TypeError: >>> from weakref import WeakMethod >>> WeakMethod(lambda: None) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python3.4/weakref.py", line 49, in __new__ .format(type(meth))) from None TypeError: argument should be a bound method, not <class 'function'> This check uses duck typing, so you could perhaps write a method-like class with __self__ and __func__ attributes and pass that to the WeakMethod constructor in the case of non-methods. There's a bigger issue with this however, which is that WeakMethod works by keeping weak references to *both* the object and the function, meaning that as soon as the function has no other references, the WeakMethod expires even if the object is still alive. This isn't a problem for methods because it's the transience of the method object, not the underlying function, that WeakMethod seeks to work around. But it doesn't by itself do anything to solve the problem of closures or lambdas that may themselves be transient. Revisiting the implementation I suggested previously, I want to make a correction. This would be better solved with a WeakValueDictionary: class Listenable: def __init__(self): self._callbacks = weakref.WeakValueDictionary() def listen(self, callback, owner=None): if owner is None: if isinstance(callback, types.MethodType): owner = weakref.WeakMethod(callback) else: owner = callback # TODO: Should anything happen if the callback is already in the dict? self._callbacks[callback] = owner def do_callbacks(self, message): for callback in self._callbacks.keys(): callback(message) This approach has two benefits over the previous one: it simplifies the callback management a bit, and it avoids making the assumption that the owner is hashable (it assumes instead that the callback is hashable, but I think that's reasonable). -- https://mail.python.org/mailman/listinfo/python-list