problem with weakref.proxy

Discussion in 'Python' started by Walter Haslbeck, Jan 31, 2004.

  1. Hello,

    I'm a completly Python newbie. As a first learning project I want to port
    an game-engine I have writte some time ago in pure C to Python using OO
    methods.

    So I created a base-class 'GOb' (GameObject). This class should have
    a sorted list of all instances stored as as class-attribte __olist[].

    When I add a reference of the new created object in the constructor
    (with GOb.__olist.append(self)) I have 2 references to each created
    instance and if I 'del' the instance the destructor is not called,
    because __olist[] holds another reference to that object.

    Now I got to tip to use the weakref module. Well I thought this should
    be exactly what I need and changed the program to add not a reference
    to the instances but a weakref.proxy.

    So now my instances are deleted really deleted when I use 'del', but:
    How do get corresponding weakref.proxy object out of __olist[]?

    I tried to use the callback parameter from weakref.proxy, but at the
    time when the callback takes place, the proxy object is allready 'dead',
    I get an Exception when I try to remove the proxy-instance from __olist[]:

    Exception exceptions.ReferenceError: 'weakly-referenced object no
    longer exists' in <function proxy_callback at 0x4040c02c> ignored

    And if I iterate throu all objects in __olist[] I get an
    'ReferenceError: weakly-referenced object no longer exists'


    please look at the following source:

    ################################################################################

    import weakref

    class GOb:

    __olist=[]

    def c_show_all():
    print "all GObs, sorted by priority:"
    for i in GOb.__olist:
    i.show()

    def proxy_callback(x):
    print "weakref.proxy callback"
    GOb.__olist.remove(x)

    proxy_callback=staticmethod(proxy_callback)
    c_show_all=staticmethod(c_show_all)

    def __init__(self, name="GOB", priority=0):
    self.priority=priority
    self.name=name
    ref=weakref.proxy(self, GOb.proxy_callback)
    GOb.__olist.append(ref)
    GOb.__olist.sort()

    def __del__(self):
    print "Destruktor called for GOB " + self.name

    def show(self):
    print self.name + " " + str(self.priority)

    def __cmp__(self, other):
    if self.priority < other.priority:
    return -1
    elif self.priority == other.priority:
    return 0
    else:
    return 1

    if __name__ == '__main__':

    a=GOb("T1", 0)
    b=GOb("T2", 2)
    c=GOb("T3", 1)

    GOb.c_show_all()
    print "delete T1:"
    del a
    GOb.c_show_all()

    ################################################################################

    any hints?

    Walter
     
    Walter Haslbeck, Jan 31, 2004
    #1
    1. Advertising

  2. Walter Haslbeck

    Jp Calderone Guest

    On Sat, Jan 31, 2004 at 02:52:45PM +0100, Walter Haslbeck wrote:
    > Hello,
    >
    > I'm a completly Python newbie. As a first learning project I want to port
    > an game-engine I have writte some time ago in pure C to Python using OO
    > methods.
    >
    > So I created a base-class 'GOb' (GameObject). This class should have
    > a sorted list of all instances stored as as class-attribte __olist[].
    >
    > When I add a reference of the new created object in the constructor
    > (with GOb.__olist.append(self)) I have 2 references to each created
    > instance and if I 'del' the instance the destructor is not called,
    > because __olist[] holds another reference to that object.
    >
    > Now I got to tip to use the weakref module. Well I thought this should
    > be exactly what I need and changed the program to add not a reference
    > to the instances but a weakref.proxy.
    >
    > So now my instances are deleted really deleted when I use 'del', but:
    > How do get corresponding weakref.proxy object out of __olist[]?
    >
    > I tried to use the callback parameter from weakref.proxy, but at the
    > time when the callback takes place, the proxy object is allready 'dead',
    > I get an Exception when I try to remove the proxy-instance from __olist[]:


    A WeakKeyDictionary or WeakValueDictionary might be a better fit for your
    problem. There is no need for you to remove the object from these manually.
    When the object is no longer referenced anywhere else, it also no longer
    belongs to the dictionary.

    >>> class foo: pass

    ...
    >>> import weakref
    >>> d = weakref.WeakValueDictionary()
    >>> x = foo()
    >>> d['key'] = x
    >>> print d.items()

    [('key', <__main__.foo instance at 0x401eeb2c>)]
    >>> del x
    >>> print d.items()

    []
    >>>


    Jp
     
    Jp Calderone, Jan 31, 2004
    #2
    1. Advertising

  3. Walter Haslbeck

    Peter Otten Guest

    Walter Haslbeck wrote:

    > Hello,
    >
    > I'm a completly Python newbie. As a first learning project I want to port
    > an game-engine I have writte some time ago in pure C to Python using OO
    > methods.
    >
    > So I created a base-class 'GOb' (GameObject). This class should have
    > a sorted list of all instances stored as as class-attribte __olist[].
    >
    > When I add a reference of the new created object in the constructor
    > (with GOb.__olist.append(self)) I have 2 references to each created
    > instance and if I 'del' the instance the destructor is not called,
    > because __olist[] holds another reference to that object.
    >
    > Now I got to tip to use the weakref module. Well I thought this should
    > be exactly what I need and changed the program to add not a reference
    > to the instances but a weakref.proxy.
    >
    > So now my instances are deleted really deleted when I use 'del', but:
    > How do get corresponding weakref.proxy object out of __olist[]?
    >
    > I tried to use the callback parameter from weakref.proxy, but at the
    > time when the callback takes place, the proxy object is allready 'dead',
    > I get an Exception when I try to remove the proxy-instance from __olist[]:
    >
    > Exception exceptions.ReferenceError: 'weakly-referenced object no
    > longer exists' in <function proxy_callback at 0x4040c02c> ignored
    >
    > And if I iterate throu all objects in __olist[] I get an
    > 'ReferenceError: weakly-referenced object no longer exists'
    >
    >
    > please look at the following source:


    [...]

    I'd recommend being lazy and using a WeakValueDictionary instead of building
    the machinery on your own. Your code would then look similar to the
    following:

    import weakref

    class GOb:

    all = weakref.WeakValueDictionary()

    def c_show_all():
    print "all GObs, sorted by priority:"
    values = GOb.all.values()
    values.sort()
    for i in values:
    print i

    c_show_all = staticmethod(c_show_all)

    def __init__(self, name="GOB", priority=0):
    self.priority = priority
    self.name = name
    GOb.all[id(self)] = self

    def __del__(self):
    print "Destruktor called for GOB " + self.name

    def __str__(self):
    return self.name + " " + str(self.priority)

    def __cmp__(self, other):
    return cmp(self.priority, other.priority)

    if __name__ == '__main__':

    a=GOb("T1", 0)
    b=GOb("T2", 2)
    c=GOb("T3", 1)

    GOb.c_show_all()
    print "delete T1:"
    del a
    GOb.c_show_all()


    Peter
     
    Peter Otten, Jan 31, 2004
    #3
  4. Walter Haslbeck

    Peter Otten Guest

    Peter Otten wrote:

    > I'd recommend being lazy and using a WeakValueDictionary instead of
    > building the machinery on your own. Your code would then look similar to


    If you want to keep your original design, just use ref instead of proxy:

    import weakref

    class GOb:

    __olist=[]

    def c_show_all():
    print "all GObs, sorted by priority:"
    for i in GOb.__olist:
    i().show()

    def proxy_callback(x):
    print "weakref.proxy callback"
    GOb.__olist.remove(x)

    proxy_callback=staticmethod(proxy_callback)
    c_show_all=staticmethod(c_show_all)

    def __init__(self, name="GOB", priority=0):
    self.priority=priority
    self.name=name
    ref=weakref.ref(self, GOb.proxy_callback)
    GOb.__olist.append(ref)
    GOb.__olist.sort(lambda x, y: cmp(x(), y()))

    def __del__(self):
    print "Destruktor called for GOB " + self.name

    def show(self):
    print self.name + " " + str(self.priority)

    def __cmp__(self, other):
    if self.priority < other.priority:
    return -1
    elif self.priority == other.priority:
    return 0
    else:
    return 1

    if __name__ == '__main__':

    a=GOb("T1", 0)
    b=GOb("T2", 2)
    c=GOb("T3", 1)

    GOb.c_show_all()
    print "delete T1:"
    del a
    GOb.c_show_all()

    The line that failed in your original version is

    GOb.__olist.remove(x)

    because x is found in __olist by comparing against the list items - and the
    proxy automatically delegates this to the no longer existing object. With
    ref you have to explicitly dereference by calling (as seen in
    __olist.sort() in the __init__() method).
    As that step is not performed by the list.remove() method, only ref instead
    of GOb instances are compared and the callback succeeds.

    Peter
     
    Peter Otten, Jan 31, 2004
    #4
  5. Peter Otten <> wrote:

    > I'd recommend being lazy and using a WeakValueDictionary instead of building
    > the machinery on your own. Your code would then look similar to the
    > following:


    thanks for the tip, but:

    [...]
    > def c_show_all():
    > print "all GObs, sorted by priority:"
    > values = GOb.all.values()
    > values.sort()

    [...]

    I don't want the list to be sorted in the method c_show_all, but when a
    new instance is created. Sort a list is an expensive operation, and
    c_show_all will be called on every game frame, but new objects are
    created much less.

    Walter
     
    Walter Haslbeck, Jan 31, 2004
    #5
  6. Peter Otten <> wrote:

    > If you want to keep your original design, just use ref instead of proxy:


    Thanks! Thats what I was looking for!

    And: after I posted the original article I tried another method:

    I didn't use weakref, but put a real reference of the instance
    into __olist and checked in c_show_all with sys.getrefcount()
    if the object is referenced by other names. If not, I removed
    the object from __olist[].

    Well, that worked. But I like the weakref.ref method much more!

    Walter
     
    Walter Haslbeck, Jan 31, 2004
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ames Andreas (MPA/DF)

    weakref and thread safety (in python 2.1)

    Ames Andreas (MPA/DF), Jul 22, 2003, in forum: Python
    Replies:
    1
    Views:
    438
    Duncan Booth
    Jul 22, 2003
  2. William Trenker

    Using weakref with execfile?

    William Trenker, Dec 21, 2003, in forum: Python
    Replies:
    1
    Views:
    282
    Martin v. Loewis
    Dec 22, 2003
  3. ali

    what is the use of weakref?

    ali, Jan 30, 2004, in forum: Python
    Replies:
    2
    Views:
    287
    Duncan Booth
    Jan 30, 2004
  4. John Nagle
    Replies:
    2
    Views:
    1,049
    John Nagle
    Feb 26, 2007
  5. Nicholas Cole

    weakref.proxy behaviour in python 3.0

    Nicholas Cole, Aug 21, 2010, in forum: Python
    Replies:
    3
    Views:
    493
    Mark Dickinson
    Aug 21, 2010
Loading...

Share This Page