[PySide] QObject.destroyed() is not emitted

Alexey Vihorev vihorev at gmail.com
Thu Nov 29 16:48:21 CET 2012

Hi, Christian!
Thanks, nice find, but... I hit the next hurdle trying to go this way. The signal QObject.destroyed(obj) is passing no arguments (probably because obj is already destroyed), so my static method has nothing to work on. Which kind of devaluates the whole idea, IMHO. And in PyQt4 it *does* pass the object. Even more: in PyQt4 there is no need for static method approach, as it works perfectly with instance methods:

from PyQt4 import QtGui,QtCore

class MyModel(QtCore.QAbstractTableModel):
    def beforeDestruction(self, *arg):

if __name__ == '__main__':
    import sys
    app = QtGui.QApplication(sys.argv)
    window = QtGui.QWidget()
    model = MyModel(window)

-----Original Message-----
From: Christian Tismer [mailto:tismer at stackless.com] 
Sent: 29 ноября 2012 г. 16:54
To: Alexey Vihorev
Cc: 'Stephan Deibel'; pyside at qt-project.org
Subject: Re: [PySide] QObject.destroyed() is not emitted

Hi Alexey,

found it! :-)

This is in fact a PySide quirk:

Your deletion method is an attribute that lives inside the object to be deleted, and that is the problem:
Destruction seems not to care about the order of destruction, and the __dict__ that also holds the onDestroy bound method gets destructed before it is called.

I tried that for other kinds of objects, it is always the same.
If you use a function from elsewhere, it works.

I tried to put the onDestroy method into an external list, with no success, because that reference disables destruction.

A general work-around could use a weakref, but for your case I think this simple solution is fine:

from PySide.QtCore import QAbstractTableModel

class MyModel(QAbstractTableModel):
     def __init__(self, *args):
         super(MyModel, self).__init__(*args)
     def onDestroy():

m = MyModel()
del m

prints "destroyed" :=)

cheers - chris

On 11/29/12 1:05 PM, Alexey Vihorev wrote:
> Ok, let's get less abstract. I got a QTableModel that has to free up some external resources upon its destruction (rollback/close a DB transaction).  In this particular case It's parent is QMdiSubWindow with self.setAttribute(QtCore.Qt.WA_DeleteOnClose), but that is not necessary  - it can be used inside complex widgets, etc.  The code is trivial, but does not work:
> class MyModel(QAbstractTableModel):
>      def onDestroy(self):
>          #Do some housekeeping
>      def __init__(self, entity_cls, parent=None, load=True, criteria=None):
>          ...	
>          self.destroyed.connect(self.onDestroy)
>          ...
> -----Original Message-----
> From: Christian Tismer [mailto:tismer at stackless.com]
> Sent: 29 ноября 2012 г. 6:25
> To: Alexey Vihorev
> Cc: 'Stephan Deibel'; pyside at qt-project.org
> Subject: Re: [PySide] QObject.destroyed() is not emitted
> Alexey,
> there is not enough context to see your problem.
> The behavior in our similar examples is correct:
> Noting gets destroyed until we release the references from Python.
> As long as you have a reference, no destruction occurs.
> By the assignment
>     obj = QtCore.Object(),
> you create a reference. You do not actively destroy the object by
>     del ob
> but you just remove one reference. And because nothing else has a reference to it, _then_ the destruction takes place.
> The question is about the interaction with other objects.
> If everything is correct with PySide (which is certainly still not), then destruction should just work automatically when it's time.
> So please give us more of your code.
> We cannot see what the real problem is.
> cheers - chris
> On 29.11.12 04:26, Alexey Vihorev wrote:
>> Yes, I tried something like that:
>> def onDestroy(*args):
>>       print('destroyed')
>> obj = QtCore.QObject()
>> obj.destroyed.connect(onDestroy)
>> obj2 = QtCore.QObject(obj)
>> obj2.destroyed.connect(onDestroy)
>> del(obj)
>> In this case onDestroy() is called twice, just as it should. But once 
>> again
>> - omit the last line and nothing Is called. So for it to work 
>> explicit destruction must be called at the top of the chain. Which is 
>> problematic in my case.
>> -----Original Message-----
>> From: Christian Tismer [mailto:tismer at stackless.com]
>> Sent: 29 ноября 2012 г. 0:58
>> To: Alexey Vihorev
>> Cc: 'Stephan Deibel'; pyside at qt-project.org
>> Subject: Re: [PySide] QObject.destroyed() is not emitted
>> Hi Alexey,
>> I tried your example and added a parent.
>> Right now it looks exactly as it should be:
>>    >>> def onDestroy(*args):
>> ...     print('destroyed')
>> ...
>>    >>> obj = QtCore.QObject()
>>    >>> obj.destroyed.connect(onDestroy) True
>>    >>> par = QtCore.QObject()
>>    >>> obj.setParent(par)
>>    >>> del obj
>>    >>> del par
>> destroyed
>>    >>>
>> This is PySide on Mac OS X,
>>    >>> PySide.__version__
>> '1.1.2'
>>    >>> QtCore.__version__
>> '4.8.3'
>>    >>>
>> Maybe you have some more references to the object?
>> For simple refcount checking, you can use sys.getrefcount .
>>    >>> g=sys.getrefcount
>>    >>> g(obj)
>> 2
>> Note that this prints 2 because of the reference from the call. So 
>> the object should go away when the one real reference goes away.
>> Maybe you have a different problem, involving more objects?
>> ---------
>> By the way, PySide seems to be not happy with reference cycles, while 
>> pure python is ok with that:
>>    >>> obj = QtCore.QObject()
>>    >>> obj.setParent(obj)
>>    >>> g(obj)
>> 2
>> Eeek, that should be 3.
>> And if fact.......
>>    >>> del(obj)
>> Segmentation fault: 11
>> ciao -- Chris
>> On 11/28/12 9:24 PM, Alexey Vihorev wrote:
>>> Hi!
>>> Well, I understand that if what I need to do is achievable with 
>>> explicit deletion,  I should go for it :) The problem is that in my 
>>> case the deletion of the object is triggered by deletion of another 
>>> object - its parent. But I can't catch the deletion event - neither 
>>> of the
>> object nor its parent.
>>> That's the problem. The whole reason I started looking into that is 
>>> that one of my objects needed to free some external resources when
>> destroyed.
>>> -----Original Message-----
>>> From: Stephan Deibel [mailto:sdeibel at wingware.com]
>>> Sent: 28 ноября 2012 г. 16:33
>>> To: Alexey Vihorev
>>> Cc: pyside at qt-project.org
>>> Subject: Re: [PySide] QObject.destroyed() is not emitted
>>> Alexey Vihorev wrote:
>>>> Got problems with the following code:
>>>> from PySide import QtCore
>>>> def onDestroy(*args):
>>>> print('destroyed')
>>>> obj = QtCore.QObject()
>>>> obj.destroyed.connect(onDestroy)
>>>> The onDestroy() method is not called, unless del(obj) is called 
>>>> explicitly. In PyQt4 it is called without del(obj). Is that a bug 
>>>> or intended behavior? I'm using Qt 4.8.2, PySide 1.1.2 32bit, 
>>>> Windows
>>>> 7-64
>>> Since no one responded I'll take a stab at this:
>>> I suspect the life cycle of the QObject under PySide is a little 
>>> different and the instance will be deleted later during garbage 
>>> collection and not immediately when it goes out of scope. I'm 
>>> actually not sure why that is happening in PyQt (seems slightly surprising).
>>> In general if you want to make sure an instance is deleted at a 
>>> particular moment in time, you need to delete it explicitly. By 
>>> that, I mean calling some sort of delete method (in PySide I think 
>>> it's
>>> shiboken.delete(obj) and not just "del obj". The latter just deletes 
>>> your reference to the instance but doesn't destroy the instance 
>>> until all other references are gone and it is garbage collected. Of 
>>> course calling
>>> shiboken.delete(obj) will be a problem if you still have other 
>>> references and try to use them!
>>> There is also obj.deleteLater() which marks an object for deletion 
>>> but it's not deleted until the event loop is reached again. 
>>> Depending on what you're doing this may be a safer way to delete it.
>>> At first I thought this might be a refcount bug in PySide. However, 
>>> I'm thinking not since "del obj" just deletes your reference to it 
>>> and if there were extra references hanging around (either on purpose 
>>> or as a result of a refcount bug) then it would not be deleting the 
>>> instance at all even after "del obj".
>>> I don't understand PySide internals that well so it's possible I'm 
>>> missing some subtlety here. I'm going more on my knowledge of Python 
>>> in
>> general.
>>> - Stephan
>>> _______________________________________________
>>> PySide mailing list
>>> PySide at qt-project.org
>>> http://lists.qt-project.org/mailman/listinfo/pyside

Christian Tismer             :^)   <mailto:tismer at stackless.com>
Software Consulting          :     Have a break! Take a ride on Python's
Karl-Liebknecht-Str. 121     :    *Starship* http://starship.python.net/
14482 Potsdam                :     PGP key -> http://pgp.uni-mainz.de
phone +49 173 24 18 776  fax +49 (30) 700143-0023
PGP 0x57F3BF04       9064 F4E1 D754 C2FF 1619  305B C09C 5A3B 57F3 BF04
       whom do you want to sponsor today?   http://www.stackless.com/

More information about the PySide mailing list