Resolve circular reference

Discussion in 'Python' started by moerchendiser2k3, Jan 7, 2011.

  1. Hi,

    I have a small problem with circular references. I embedded Python
    into my app and I have two types which are flagged with
    Py_TPFLAGS_BASETYPE so I can inherit Python types from these types.
    Lets call my C types A and B.


    Here is the dependency:

    class Foo(A):
    e=Bar()

    class Bar(B):
    def __init__(self, p):
    self.p=p
    i=Foo()
    j=Bar(i)

    Everything works fine, the problem starts when I start to make a
    circular reference in Python. In my embedded app I have a reference to
    instance A. When I decref this reference its still alive because the
    instance j(Bar) makes this object still alive. Is there any chance to
    force this? Because without A the instance A shouldnt be alive
    anymore. Thanks for any hint!!

    Bye
    moerchendiser2k3, Jan 7, 2011
    #1
    1. Advertising

  2. moerchendiser2k3

    MRAB Guest

    On 07/01/2011 02:24, moerchendiser2k3 wrote:
    > Hi,
    >
    > I have a small problem with circular references. I embedded Python
    > into my app and I have two types which are flagged with
    > Py_TPFLAGS_BASETYPE so I can inherit Python types from these types.
    > Lets call my C types A and B.
    >
    >
    > Here is the dependency:
    >
    > class Foo(A):
    > e=Bar()
    >
    > class Bar(B):
    > def __init__(self, p):
    > self.p=p
    > i=Foo()
    > j=Bar(i)
    >
    > Everything works fine, the problem starts when I start to make a
    > circular reference in Python. In my embedded app I have a reference to
    > instance A. When I decref this reference its still alive because the
    > instance j(Bar) makes this object still alive. Is there any chance to
    > force this? Because without A the instance A shouldnt be alive
    > anymore. Thanks for any hint!!
    >

    Force what?

    j refers to i, i refers to Foo, Foo refers to A. Therefore A should be
    alive.
    MRAB, Jan 7, 2011
    #2
    1. Advertising

  3. > Force what?
    >
    > j refers to i, i refers to Foo, Foo refers to A. Therefore A should be
    > alive.


    Oh, sorry. Force the deletion of A.
    moerchendiser2k3, Jan 7, 2011
    #3
  4. > Force what?
    > j refers to i, i refers to Foo, Foo refers to A. Therefore A should be
    > alive.



    Oh, sorry. Force the deletion of instance Foo(A) and Bar(B).
    moerchendiser2k3, Jan 7, 2011
    #4
  5. moerchendiser2k3

    Carl Banks Guest

    On Jan 7, 3:58 am, moerchendiser2k3 <googler.
    > wrote:
    > > Force what?
    > > j refers to i, i refers to Foo, Foo refers to A. Therefore A should be
    > > alive.

    >
    > Oh, sorry. Force the deletion of instance Foo(A) and Bar(B).


    If you don't want j to keep i alive, you should look at weak
    referencing. (Look at the documentation for the weakref module.
    Also, this has nothing to do with A and B being C-defined types; this
    exact same behavior would happen even with Python types.)


    Carl Banks
    Carl Banks, Jan 7, 2011
    #5
  6. so there is no chance without using weakrefs?
    any ideas, tips, workarounds how I might handle this?

    bye, moerchendiser2k3
    moerchendiser2k3, Jan 10, 2011
    #6
  7. moerchendiser2k3

    Carl Banks Guest

    On Jan 10, 12:21 am, moerchendiser2k3 <googler.
    > wrote:
    > so there is no chance without using weakrefs?
    > any ideas, tips, workarounds how I might handle this?


    No, sorry: as long as a reference to an object exists, the object is
    never deleted. There is no way to get around this.

    Python in general isn't designed to allow for exact control over the
    destruction of objects. Even in CPython, which uses reference
    counting, there are a bunch of situations where a reference might be
    stored to an object that keeps it alive. (Unexpected locations where
    a stray reference might exist: an unpickler object, the _ symbol in
    the interactive shell.) Other implementations, like Jython and
    IronPython, don't use reference counting and don't provide for any
    particular time at all for an object to be destroyed.

    The recommended way to ensure timely release of resources in Python is
    to provide a method (such as close or finalize) to explicity release
    the resource--the object then lives on in a zombie state. The with
    statement can be used in many cases to avoid the need to call this
    method explicitly. For example, if you were to run this code in
    Python:

    with open(filename) as f:
    g = f
    print g

    It would print <closed file 'whatever' ...>. The object still exists
    because there is a reference to it, but the file has been closed.


    If you can tell us why it's so important that the object be destroyed
    at that given time, even while a reference to it exists, maybe we can
    give you better suggestions.


    Carl Banks
    Carl Banks, Jan 10, 2011
    #7
  8. > If you can tell us why it's so important that the object be destroyed
    > at that given time, even while a reference to it exists, maybe we can
    > give you better suggestions.


    Thanks for your answer! In my case the types A and B (in my example
    above)
    are a dialog and a dialog widget. At a special time I have to close
    and
    destroy all dialogs but this does not happen because the widget keeps
    the dialog alive. I have the reference to the dialog
    but after I closed the dialogs I also would like to destroy them
    because
    they have to free some special ressources.

    Thanks a lot!! Bye, moerchendiser2k3
    moerchendiser2k3, Jan 10, 2011
    #8
  9. moerchendiser2k3, 10.01.2011 18:55:
    >> If you can tell us why it's so important that the object be destroyed
    >> at that given time, even while a reference to it exists, maybe we can
    >> give you better suggestions.

    >
    > Thanks for your answer! In my case the types A and B (in my example
    > above)
    > are a dialog and a dialog widget. At a special time I have to close
    > and
    > destroy all dialogs but this does not happen because the widget keeps
    > the dialog alive. I have the reference to the dialog
    > but after I closed the dialogs I also would like to destroy them
    > because they have to free some special ressources.


    Objects within a reference cycle will eventually get cleaned up, just not
    right away and not in a predictable order.

    If you need immediate cleanup, you should destroy the reference cycle
    yourself, e.g. by removing the widgets from the dialog when closing it.

    Stefan
    Stefan Behnel, Jan 10, 2011
    #9
  10. On Jan 10, 7:18 pm, Stefan Behnel <> wrote:
    > moerchendiser2k3, 10.01.2011 18:55:
    >
    > >> If you can tell us why it's so important that the object be destroyed
    > >> at that given time, even while a reference to it exists, maybe we can
    > >> give you better suggestions.

    >
    > > Thanks for your answer! In my case the types A and B (in my example
    > > above)
    > > are a dialog and a dialog widget. At a special time I have to close
    > > and
    > > destroy all dialogs but this does not happen because the widget keeps
    > > the dialog alive. I have the reference to the dialog
    > > but after I closed the dialogs I also would like to destroy them
    > > because they have to free some special ressources.

    >
    > Objects within a reference cycle will eventually get cleaned up, just not
    > right away and not in a predictable order.
    >
    > If you need immediate cleanup, you should destroy the reference cycle
    > yourself, e.g. by removing the widgets from the dialog when closing it.
    >
    > Stefan


    The PyWidget type does not own the widget, it just points to it. I
    have an
    idea, would this fix the problem?

    I destroy the internal dictionary of the dialog which points to other
    PyObjects?
    Then I would cut the dependency.
    moerchendiser2k3, Jan 10, 2011
    #10
  11. moerchendiser2k3, 10.01.2011 22:19:
    > On Jan 10, 7:18 pm, Stefan Behnel wrote:
    >> moerchendiser2k3, 10.01.2011 18:55:
    >>
    >>>> If you can tell us why it's so important that the object be destroyed
    >>>> at that given time, even while a reference to it exists, maybe we can
    >>>> give you better suggestions.

    >>
    >>> Thanks for your answer! In my case the types A and B (in my example
    >>> above)
    >>> are a dialog and a dialog widget. At a special time I have to close
    >>> and
    >>> destroy all dialogs but this does not happen because the widget keeps
    >>> the dialog alive. I have the reference to the dialog
    >>> but after I closed the dialogs I also would like to destroy them
    >>> because they have to free some special ressources.

    >>
    >> Objects within a reference cycle will eventually get cleaned up, just not
    >> right away and not in a predictable order.
    >>
    >> If you need immediate cleanup, you should destroy the reference cycle
    >> yourself, e.g. by removing the widgets from the dialog when closing it.
    >>
    >> Stefan

    >
    > The PyWidget type does not own the widget, it just points to it. I
    > have an idea, would this fix the problem?
    >
    > I destroy the internal dictionary of the dialog which points to other
    > PyObjects? Then I would cut the dependency.


    Sure, that should work.

    Stefan
    Stefan Behnel, Jan 11, 2011
    #11
  12. On 2011-01-07 03:24, moerchendiser2k3 wrote:
    > Everything works fine, the problem starts when I start to make a
    > circular reference in Python.


    I didn't quite grok your example, but concerning CPython GC & circular
    references...

    >>> import gc
    >>> class X:

    .... def __del__(self):
    .... print 'Deleted', self
    ....
    >>> a = X()
    >>> del a

    Deleted <__main__.X instance at 0x00CCCF80>
    >>> a=X()
    >>> b=X()
    >>> a.b=b
    >>> b.a=a
    >>> del a
    >>> gc.collect()

    0
    >>> del b
    >>> gc.collect()

    4
    >>>
    Magnus Lyckå, Jan 13, 2011
    #12
  13. Magnus Lyckå <> writes:

    >>>> a = X()
    >>>> del a

    > Deleted <__main__.X instance at 0x00CCCF80>
    >>>> a=X()
    >>>> b=X()
    >>>> a.b=b
    >>>> b.a=a
    >>>> del a
    >>>> gc.collect()

    > 0
    >>>> del b
    >>>> gc.collect()

    > 4


    If your method has a __del__ at all, the automatic cyclic collector is
    disabled. It detects the cycle, but it only stores the objects in
    gc.garbage, to give you a chance to do something about them, such as
    break the cycle(s) yourself. For example:

    >>> class X(object):

    .... def __del__(self):
    .... print 'deleted', self
    ....
    >>> a, b = X(), X()
    >>> a.cycle = b
    >>> b.cycle = a
    >>> del a, b
    >>> import gc
    >>> gc.collect()

    4
    >>> gc.garbage

    [<__main__.X object at 0xb76d84cc>, <__main__.X object at 0xb76d980c>]
    >>> del gc.garbage[0].cycle
    >>> del gc.garbage[:]

    deleted <__main__.X object at 0xb76d980c>
    deleted <__main__.X object at 0xb76d84cc>
    Hrvoje Niksic, Jan 14, 2011
    #13
    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. Per
    Replies:
    4
    Views:
    640
  2. Steven T. Hatton
    Replies:
    3
    Views:
    8,939
    Steven T. Hatton
    Jun 5, 2004
  3. Kiuhnm
    Replies:
    16
    Views:
    741
    Jonathan Mcdougall
    Jan 3, 2005
  4. =?ISO-8859-1?Q?Ricardo_Palomares_Mart=EDnez?=

    Repost: Using EntityResolver to NOT resolve a PE Reference

    =?ISO-8859-1?Q?Ricardo_Palomares_Mart=EDnez?=, Aug 19, 2006, in forum: Java
    Replies:
    0
    Views:
    440
    =?ISO-8859-1?Q?Ricardo_Palomares_Mart=EDnez?=
    Aug 19, 2006
  5. Replies:
    1
    Views:
    10,147
Loading...

Share This Page