connect()'s refcounting behavior seems buggy, and should be documented
Yuya Nishihara
yuya at tcha.org
Sat Mar 19 10:40:12 GMT 2022
On Sat, 19 Mar 2022 10:04:49 +0000, Phil Thompson wrote:
> On 19/03/2022 02:28, Kovid Goyal wrote:
> > On Fri, Mar 18, 2022 at 05:26:13PM +0000, Phil Thompson wrote:
> >> I've changed the PyQt6 behaviour to keep a reference to bound methods.
> >> I'm
> >> not going to change PyQt5 as stability (avoiding unexpected
> >> consequences) is
> >> more important than correctness so late in its lifecycle.
> >
> > Is the reference a weak or a strong reference? If its a strong
> > reference
> > it will create reference cycles. Something as simple as:
> >
> > class Widget(QDialog):
> >
> > def __init__(self):
> > QDialog.__init__(self)
> > self.bb = QDialogButtonBox(self)
> > self.bb.accepted.connect(self.accept)
> >
> > def accept(self):
> > ...
> >
> > is now a reference cycle that the python garbage collector cannot
> > collect.
>
> The garbage collector should be able to detect and break such cycles.
> Can you show a complete script based on the fragment above that
> demonstrates a problem (I can't so far).
Hi, I thought about __del__, but apparently it's no longer problem on
Python 3.5+.
https://docs.python.org/3/library/gc.html#gc.garbage
One problem I can think of is that timer or large resources held by
the Widget won't be released until GC run.
class Widget(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.bb = QDialogButtonBox(self)
self.bb.accepted.connect(lambda: self.accept()) # strong ref
self.t = QTimer()
self.t.timeout.connect(self.onTimeout)
self.t.start(100)
#def __del__(self):
# print('del')
def accept(self):
pass
def onTimeout(self):
print('run some heavy op on timeout')
def kick():
w = Widget()
w.exec()
print('w should ideally be deleted here')
def run_gc():
print('gc')
gc.collect()
def main():
app = QApplication(sys.argv)
app.setQuitOnLastWindowClosed(False)
QTimer.singleShot(0, kick)
gcTimer = QTimer()
gcTimer.timeout.connect(run_gc)
gcTimer.start(5000)
app.exec()
More information about the PyQt
mailing list