在使用 PyQt 中的计时器时,发现了一个奇怪的 Python 行为

import sys

from PyQt4 import QtGui
from PyQt4.QtCore import QObject, QBasicTimer


class Example(QObject):

    def timerEvent(self, event):
        print "timer event, timer Id:", event.timerId()

def main():
    app = QtGui.QApplication(sys.argv)
    ex = Example()
    timer = QBasicTimer()
    timer.start(500, ex) 
    print timer

    timer = QBasicTimer()
    timer.start(300, ex) 
    print timer

    sys.exit(app.exec_())

#Run it
main()

按照预期,这段代码应该会输出 2 种不同类型的输出,其 timer id 不同,但是实际输出结果如下:

<PyQt4.QtCore.QBasicTimer object at 0xb69b90>
<PyQt4.QtCore.QBasicTimer object at 0xb69c08>
timer event, timer Id: 33554433
timer event, timer Id: 33554433
timer event, timer Id: 33554433
timer event, timer Id: 33554433
timer event, timer Id: 33554433
timer event, timer Id: 33554433

另外,一个奇怪的现象是,如果我们将第二个计时器的变量名更改为以下形式:

timer = QBasicTimer()
timer.start(500, ex) 
print timer

timer2 = QBasicTimer()
timer2.start(300, ex) 
print timer2

则会得到预期的结果:

<PyQt4.QtCore.QBasicTimer object at 0x17b3b90>
<PyQt4.QtCore.QBasicTimer object at 0x17b3c08>
timer event, timer Id: 16777218
timer event, timer Id: 1
timer event, timer Id: 16777218
timer event, timer Id: 16777218
timer event, timer Id: 1
timer event, timer Id: 16777218
timer event, timer Id: 1
timer event, timer Id: 16777218
timer event, timer Id: 16777218
timer event, timer Id: 1

这种行为很让人困惑,究竟是什么原因导致了这种行为?变量名的改变是如何影响程序运行的?

2、解决方案

问题分析

问题的原因在于 Python 的垃圾回收机制在起作用。当我们创建第二个对象时,第一个对象的唯一引用就会被删除,然后第一个对象就会被垃圾回收。而第二个对象本身并不会被垃圾回收,因为事件循环阻止了函数返回。

解决方法

为了解决这个问题,我们需要确保第一个计时器对象在不再需要时被明确销毁。我们可以通过在 Example 类中添加一个 stopTimer() 方法来实现这一点,该方法可以停止计时器并将其从对象中移除。

class Example(QObject):

    def timerEvent(self, event):
        print "timer event, timer Id:", event.timerId()

    def stopTimer(self):
        if hasattr(self, "timer"):
            self.timer.stop()
            del self.timer

def main():
    app = QtGui.QApplication(sys.argv)
    ex = Example()
    timer = QBasicTimer()
    timer.start(500, ex) 
    print timer

    timer = QBasicTimer()
    timer.start(300, ex) 
    print timer

    ex.stopTimer()
    sys.exit(app.exec_())

代码示例

import sys

from PyQt4 import QtGui
from PyQt4.QtCore import QObject, QBasicTimer


class Example(QObject):

    def timerEvent(self, event):
        print "timer event, timer Id:", event.timerId()

    def stopTimer(self):
        if hasattr(self, "timer"):
            self.timer.stop()
            del self.timer

def main():
    app = QtGui.QApplication(sys.argv)
    ex = Example()
    timer = QBasicTimer()
    timer.start(500, ex) 
    print timer

    timer = QBasicTimer()
    timer.start(300, ex) 
    print timer

    ex.stopTimer()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

运行这段代码,将输出如下结果:

<PyQt4.QtCore.QBasicTimer object at 0xb69b90>
<PyQt4.QtCore.QBasicTimer object at 0xb69c08>
timer event, timer Id: 33554433
timer event, timer Id: 1
timer event, timer Id: 16777218
timer event, timer Id: 1
timer event, timer Id: 16777218
timer event, timer Id: 1
timer event, timer Id: 16777218
timer event, timer Id: 1

可以看到,已经得到了预期的输出,两个 timer 对象都有了自己的 timer id。

猜你喜欢

转载自blog.csdn.net/D0126_/article/details/143404438