在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()
根据这段代码,我本来期待看到两种不同的输出,它们的计时器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
我正在学习Python,这让我感到很困惑。是什么导致了这种情况?变量的名字怎么会影响程序呢?
1 个回答
1
我不明白你为什么觉得这个行为奇怪。事情的顺序就是这样:
ex = Example()
# timer(1) object is created
timer = QBasicTimer()
# ex object registers timer(1)
timer.start(500, ex)
print timer
# timer(2) object is created
# timer(1) object is destroyed
# timer(1) destructor unregisters timer(1)
timer = QBasicTimer()
# ex object registers timer(2)
timer.start(300, ex)
print timer
# event loop starts, 300ms later, timer(2) event is processed...
sys.exit(app.exec_())
这只是普通的Python垃圾回收在起作用。创建一个同名的第二个对象会移除对第一个对象的唯一引用,这样第一个对象就会立即被垃圾回收。而且,第二个对象不会被垃圾回收,因为事件循环阻止了函数的返回。
如果你没有阅读关于QBasicTimer的文档,我想你可能会认为这一行:
timer.start(500, ex)
会让ex
成为timer
的父对象,从而保持它的存活。但要让这个成立,QBasicTimer
必须是QObject
的子类——而实际上它并不是。
其实,QBasicTimer.start()
方法等同于这个:
def start(self, msec, obj):
self.stop()
if obj is not None:
self.id = obj.startImer(msec)