Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I weak reference methods? [duplicate]

Possible Duplicate:
Why doesn't the weakref work on this bound method?

A bit of context:

I was trying to implement an Listener (or Observer, same thing) pattern: An EventManager keeps a list of all the Listeners handlers interested in an Event. For example, a Listener object would have a onEndOfTheWorldEvent method which would be called by the EventManager each time an instance of the event class EndOfTheWorldEvent is posted. Easy.

Except that I wanted to weak reference the handlers because I don't want the EventManager to keep my handlers (bound methods) alive when the Listener was not needed anymore.

So I thought "Let's throw all the handlers in a WeakSet". I couldn't get it to work.

I dump here the code (or what's left of it when I reduce it to the minimum, here there's only one type of event and only one type of handler).

#! /usr/bin/python
"""

"""
import sys
import weakref

class Listener(object):
    def handler(self, event):
        print event

class EventManager(object):
    def __init__(self):
        self.handlers = weakref.WeakSet()
    def register(self, listener):
        print "Registering..."
        self.handlers.add(listener.handler)
        CountRefs(listener.handler)
        print "Number of handlers registered:", len(self.handlers)
        print "Registered."

def CountRefs(what):
    print "Hard count:", sys.getrefcount(what)
    print "Weak count:", weakref.getweakrefcount(what)

listener = Listener()
em = EventManager()
CountRefs(listener.handler)
em.register(listener)
CountRefs(listener.handler)

result:

Hard count: 3
Weak count: 0
Registering...
Hard count: 3
Weak count: 0
Number of handlers registered: 0
Registered.
Hard count: 3
Weak count: 0

It just looks like there's never any weak reference, and the set remains empty.

To make it even simpler:

>>> class C(object):
>>>     def blah(self):
>>>         print "blah"
>>> 
>>> c = C()
>>> w = weakref.ref(c.blah)
>>> print w
<weakref at 0x11e59f0; dead>

Can't I create weakrefs to methods at all ? If not, why not ?

So I guess a workaround would be to replace the WeakSet with a WeakKeyDictionary: key is the listener itself, and value the handler. Indeed I can weakref my Listeners. But it makes the data structure a bit more complicated, and when comes the time to broadcast the events to everybody, there's one more level in that structure to go through.

What do you think ?

like image 738
Niriel Avatar asked Aug 07 '11 20:08

Niriel


People also ask

When should you use weak reference?

Use long weak references only when necessary as the state of the object is unpredictable after finalization. Avoid using weak references to small objects because the pointer itself may be as large or larger. Avoid using weak references as an automatic solution to memory management problems.

How are weak references implemented?

When a weak reference A is created to an object B, there would be an entry in the hashtable modified or created, whose key would be the pointer to B. "Dirty" - to store a special hash-value with each object, which would be zeroed when the object is destroyed.

What is weak reference and strong reference?

A weak reference is just a pointer to an object that doesn't protect the object from being deallocated by ARC. While strong references increase the retain count of an object by 1, weak references do not. In addition, weak references zero out the pointer to your object when it successfully deallocates.

What is the use of Weakreference in Java?

Weak reference objects, which do not prevent their referents from being made finalizable, finalized, and then reclaimed. Weak references are most often used to implement canonicalizing mappings. Suppose that the garbage collector determines at a certain point in time that an object is weakly reachable.


2 Answers

Let's say you want weakrefs on a method "meth".

You can get weakrefs on it like this

weak_obj = weakref.ref(meth.im_self)
weak_func = weakref.ref(meth.im_func)

So, you can deref it like that

obj = weak_obj()
func = weak_func()

and get "meth" back with

meth = getattr(obj, func.__name__)
like image 80
dugres Avatar answered Sep 24 '22 07:09

dugres


listener.handler gives you a new bound reference to the function each time. So it gets garbage collected almost immediately.

like image 24
Neil Avatar answered Sep 24 '22 07:09

Neil