I am quite puzzled about my piece of code below (and attached), where none of the two destructors is called when terminating the program via closeEvent(). The problem disappears when I remove the assignment "self.main = parent" from MyMenuBar.__init__(). I have checked this on Mac OSX and Ubuntu.
I would actually expect the following to happen with or without the questionable assignment:
1. The MyMenuBar instance is known as a child of the MyMainWindow instance in the Qt widget hierarchy. It is thus deleted by Qt on the closeEvent().
2. On deleting that instance its reference self.main disappears, and it cannot play a role for what happens subsequently.
3. Since the instance of MyWorker lives outside the Qt widget hierarchy, I would expect its destructor to be called by Python on termination of the program.
Any clarification is highly appreciated! I am glad to have reduce my way more complicated situation to that small example, but now I am clueless.
NB: I know that there is a parent() method, and that in that situation the assignment is pointless etc.
Thomas
#!/usr/bin/env python
import sys
from PySide.QtGui import QApplication
from PySide.QtGui import QMainWindow
from PySide.QtGui import QMenuBar
class MyMainWindow(QMainWindow):
def __init__(self,parent=None):
super(MyMainWindow,self).__init__(parent)
self.worker = MyWorker()
self.setMenuBar(MyMenuBar(self))
self.show()
self.raise_()
class MyMenuBar(QMenuBar):
def __init__(self,parent=None):
super(MyMenuBar,self).__init__(parent)
self.main = parent # This line causes the problem
def __del__(self):
print "in MyMenuBar.__del__()"
class MyWorker(object):
def __del__(self):
print "in MyWorker.__del__()"
app = QApplication(sys.argv)
mainwindow = MyMainWindow()
sys.exit(app.exec_())
--
Dr. habil. Thomas Sturm
Departamento de Matematicas, Estadistica y Computacion
Universidad de Cantabria, Santander, Spain
Avda. Los Castros s/n, Room 1072, +34 693 251058
http://personales.unican.es/sturmt/
I have already found this problem in the past, this is not a PySide
problem this is a problem on python GC its not work well with cyclic
dependency and object which implement __del__ function, I do not know
the exactly problem on GC but I can reproduce your problem with this
simple code.
You can have more info about python GC on:
http://docs.python.org/library/gc.html
class MyObject(object):
def __init__(self, p):
self._parent = p
print "created", self
def __del__(self):
print "del", self
class MyObject2(object):
def __init__(self):
self._child = MyObject(self)
print "created", self
def __del__(self):
print "del", self
o = MyObject2()
del o
Then I recommend to you use a weak ref when you will store the parent
object, this will avoid the cyclic dependency. Or someone who now more
python GC can tell you how to solve this in other way, but I normally
use a proxy object.
You can get more info about weak ref from here:
http://docs.python.org/library/weakref.html
BR
> _______________________________________________
> PySide mailing list
> PyS...@lists.openbossa.org
> http://lists.openbossa.org/listinfo/pyside
>
>
--
Renato Araujo Oliveira Filho
Instituto Nokia de Tecnologia - INdT
Mobile: +55 (81) 8704-2144
_______________________________________________
PySide mailing list
PyS...@lists.openbossa.org
http://lists.openbossa.org/listinfo/pyside
It may happen, that Qt deletes the underlying C++ object, but Python
doesn't know this, and still keeps the wrapper object alive, because
there are still valid references to it. As long as there is any
reference, this object is still alive, and its __del__ method will
consequently not be invoked.
Pythons memory management should be considered non-deterministic, just
like with other managed platforms. __del__ is therefore not the
Python equivalent to a C++ destructor, and it should not be used this
way. I do know your indent in using __del__ in this specific
situation, but avoid it, if at all possible. Move cleanup work to
other methods (e.g. a event callback or a slot connected to the
"deleted" signal), which are guaranteed to be invoked in a certain
situation.
If you can't, then at least use a weak reference to refer to objects,
whose lifetime should not be controlled by Python.
> 3. Since the instance of MyWorker lives outside the Qt widget hierarchy, I would expect its destructor to be called by Python on termination of the program.
As stated in the documentation [1], the Python interpreter does not
guarantee invocation of "__del__()" for any object still alive at
interpreter termination.
Sebastian Wiesner
[1] http://docs.python.org/reference/datamodel.html#object.__del__
> It may happen, that Qt deletes the underlying C++ object, but Python
> doesn't know this, and still keeps the wrapper object alive, because
> there are still valid references to it. As long as there is any
> reference, this object is still alive, and its __del__ method will
> consequently not be invoked.
OK. This was exactly my mistake: I believed that the wrapper and Qt itself were so closely coupled that Qt's deletions would affect the corresponding Python objects.
In fact, when things did not work I intuitively put an explicit del into the close event of the main window. This resolved the problem but I never understood why. Now I do - thanks!
>
> Pythons memory management should be considered non-deterministic, just
> like with other managed platforms. __del__ is therefore not the
> Python equivalent to a C++ destructor, and it should not be used this
> way. I do know your indent in using __del__ in this specific
> situation, but avoid it, if at all possible. Move cleanup work to
> other methods (e.g. a event callback or a slot connected to the
> "deleted" signal), which are guaranteed to be invoked in a certain
> situation.
The class in question is Python-wrapped C-Code, which spawns a process. That process is a Lisp System, which occupies a considerable amount of memory. I would thus be very happy about any advice how to arrange my code in such a way that the destructor - or more generally the corresponding code for the deletion of the questionable process - is called on termination of the Python program under any circumstances - including abnormal termination due to bugs, kill -9 from outside, or whatever. Is this possible?
Thomas
In case of "kill -9" it is impossible, this signal cannot be caught by
a running process. Other cases (e.g. unexpected exceptions or the
like) can be handled, but do *not* use __del__ for this purpose!
Implement a deterministic resource management, e.g. using a context
manager, or by providing an explicit ".close()" or ".cleanup()" (or
whatever you want to call it) method, and call this method at the
appropriate places.
Sebastian Wiesner