[PyKDE] How to detect if an object has been deleted

Giovanni Bajo rasky at develer.com
Mon Sep 18 14:16:54 BST 2006


Daniel wrote:

> Is there a documented way to detect if the underlying object has been
> deleted? Here's a short example that works, but it feels a bit dirty:
>
> def is_deleted(obj):
>      try:
>          obj.name
>      except RunTimeError, ex:
>          if str(ex) == "underlying C/C++ object has been deleted":
>              return True
>          raise
>      return False
>
> There are obvious problems with this solution:
>
> - it depends on the exception message
> - it depends on an unrelated interface to produce the error (i.e.
> "name" must be a non-overridden member on the underlying object)

I'd use the following:

def is_deleted(obj):
   import sip
   try:
      sip.unwrapinstance(obj)
   except RuntimeError:
      return True
   return False

For PyQt (QObject), calling a simple function (like name(), or parent()) and
catching RuntimeError (that is, without caring of the error message) is
enough. I have succesfully used this method to implement "qtweakref", which
uses the actual lifetime of the C++ object instead of that of the Python
wrapper.

qtweakref.py:
===============================================================
from qt import *
import weakref

class qtref(weakref.ref):
    __slots__ = "_callback",

    def __new__(typ, o, callback=None):
        if not isinstance(o, QObject):
            wr = weakref.ref.__new__(weakref.ref, o, callback)
            wr.__init__(o, callback)
            return wr
        wr = weakref.ref.__new__(typ, o)
        if callback is not None:
            wr._callback = lambda: callback(wr)
            QObject.connect(o, SIGNAL("destroyed()"), wr._callback)
        return wr

    def __call__(self, *args, **kwargs):
        o = super(qtref, self).__call__(*args, **kwargs)
        if o is None:
            return None
        try:
            o.parent()
        except RuntimeError:
            return None
        return o

    def __repr__(self):
        o = self()
        if o is not None:
            return "<qtweakref at %08X; to '%.50s' at %08X>" % (id(self),
type(o).__name__, id(o))
        return "<qtweakref at %08X; dead>" % id(self)
===============================================================


>>> from qt import *
>>> import qtweakref as weakref
>>> qApp = QApplication([])
>>>

>>>
>>>
>>> a = QObject(None)
>>> r = weakref.ref(a)
>>> r
<qtweakref at 2E2048A0; to 'QObject' at 2E2014F8>
>>> a.deleteLater()
>>> qApp.processEvents()
>>> r
<qtweakref at 2E2048A0; dead>
>>> a
<qt.QObject object at 0x2E2014F8>
>>>
>>>
>>>
>>> a = QObject(None)
>>> def cb(wr):
...     print "dead:", wr
...
>>> r = weakref.ref(a, cb)
>>> a.deleteLater()
>>> qApp.processEvents()
dead: <qtweakref at 2E204870; dead>

-- 
Giovanni Bajo




More information about the PyQt mailing list