Dominic LoBue wrote on 2010-04-04 15:25: > On Sat, Mar 27, 2010 at 1:39 PM, Ian Ward <[email protected]> wrote: >> Dominic LoBue wrote on 2010-03-05 03:56: >>> Ian, >>> >>> I have a working implementation. By no means is it elegant, but it works. >>> >>> Basically instead of holding onto the specific method that is to be >>> called when a signal is recieved, we instead hold onto a tuple of >>> (ref(parentwithmethod), 'methodname'). When the signal is activated, >>> we use getattr to get an instance of the method we want and then run >>> that method. >>> >>> Working examples can be found here: >>> http://gist.github.com/322577 >>> http://gist.github.com/322576 >>> >> I just want to make sure I have a good understanding of what is >> happening with these references. The old way of tracking signals was a >> single WeakKeyDictionary: >> >> signals._connections = WeakKeyDictionary({ >> object_that_sends_signal : { >> signal_name : [ >> (callback_function, user_argument)]}}) >> >> And in common use the callback_function is a bound method on the object >> that receives the signal. >> >> This receiving object may be the last thing holding a reference to the >> sending object, however when the receiving object is removed the bound >> method keeps it alive, in turn keeping the sending object alive and >> circular references in _connections are never removed. >> >> The same thing happens with the current code, except _connections is now >> in the sending object and nothing points to the dead objects, so I >> assume they would eventually get picked up by the garbage collector. >> >> (please correct me if I'm wrong) >> > > Ian, > > The solution actually has nothing to do with where the bound method is > being kept. Keeping the signal -> method mapping in one place is > preference; I think it is a cleaner solution overall.
I agree with the preference for keeping all the mappings in one place. In my (new) tests, I haven't been able to make an implementation with everything together in one place work: http://excess.org/urwid/browser/reference_test.py Specifically the last test always fails and Urwid leaks memory. * > The problem is that bound methods reference the class they are bound > to, and in so doing they keep that class alive. The WeakKeyDictionary > doesn't do anything (at least in my case). s/class/object > To give an example, say the object_that_sends_signal from your example > is a property of object_that_receives_signal, and callback_function is > a bound method of object_that_receives_signal. This is a circular > reference: object_that_receives_signal references > object_that_sends_signal, keeping the dictionary entries alive; and > the bound method callback_function references > object_that_receives_signal, keeping it alive as well. All the nesting > that the bound_method is below prevents the weak reference from > working. * Right, but maybe we're working under different assumptions. I think it's ok for the only reference to callback function to be via a signal. Won't your code delete the object_that_receives_signal if the only reference to object_that_receives_signal is from a signal? >> One problem with your solution is that it only helps if the >> callback_function is a bound method. What if it's a normal function >> that happened to pull in a reference to the sending object from its >> enclosing scope? > > Can you give an example of what you mean? > Idle speculation, I haven't made it work(fail?) yet. Something along the lines of: def setup_my_signal_handler(): foo = ObjectThatSendsSignal() def signal_handler(f): print foo, f urwid.connect_signal(foo, 'some_signal', signal_handler) where signal_handler() has a reference to foo inherited from the enclosing function. Ian _______________________________________________ Urwid mailing list [email protected] http://lists.excess.org/mailman/listinfo/urwid
