[Urwid] Bug: Signal module create backreferences

Dominic LoBue dom.lobue at gmail.com
Sun Apr 4 15:25:58 EDT 2010


On Sat, Mar 27, 2010 at 1:39 PM, Ian Ward <ian at excess.org> 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.

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).

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.

> 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?

> I'll need to dig in to this a little more, I think..
>
> Ian
>
>
>
> So,
>
>
>
> _______________________________________________
> Urwid mailing list
> Urwid at lists.excess.org
> http://lists.excess.org/mailman/listinfo/urwid
>

I don't believe functions will be a problem because they don't have a
im_self property.

Here's an experiment to show the exact problem:

class rawr(object):
    def blarg(self): pass

a = rawr()
s = a.blarg

print a
print s.im_self


My results from an ipython session:
In [15]: s.im_self
Out[15]: <__main__.rawr object at 0x7f66e653b5d0>

In [16]: a
Out[16]: <__main__.rawr object at 0x7f66e653b5d0>


-- 
Dominic LoBue



More information about the Urwid mailing list