【问题标题】:simple IPython example raises exception on sys.exit()简单的 IPython 示例在 sys.exit() 上引发异常
【发布时间】:2012-06-08 22:10:37
【问题描述】:

我正在用 IPython 编写一些非常简单的 PySide(和 PyQt)教程。一个教程只是创建了一个带有一些滑块的窗口来演示插槽和信号。

当我关闭正在运行的演示应用程序的窗口时,我看到了这个错误:

An exception has occurred, use %tb to see the full traceback.
SystemExit: 0
To exit: use 'exit', 'quit', or Ctrl-D.

所以我运行 %tb 并得到这个:

SystemExit                                Traceback (most recent call last)
/Workspaces/scratch/<ipython-input-1-88966dcfb499> in <module>()
     33 
     34 if __name__ == "__main__":
---> 35     main()

/Workspaces/scratch/<ipython-input-1-88966dcfb499> in main()
     29         w.show()
     30         app.exec_()
---> 31         sys.exit(0)
     32 
     33 

SystemExit: 0

如果我再次尝试执行我的代码,我会得到:

RuntimeError: A QApplication instance already exists.

如果有帮助,这里是我的代码:

from PySide.QtCore import *
from PySide.QtGui import *
import sys

class MyWindow(QWidget):
    def __init__(self):
        QWidget.__init__(self, None)

        vbox = QVBoxLayout(self)

        self.slider1 = QSlider(Qt.Horizontal)
        self.slider1.setRange(0, 99)
        self.slider1.setValue(0)
        vbox.addWidget(self.slider1)

        self.slider2 = QSlider(Qt.Horizontal)
        self.slider2.setRange(0, 99)
        self.slider2.setValue(99)
        vbox.addWidget(self.slider2)

        self.slider1.valueChanged.connect(self.slider2Changed)

    def slider2Changed(self, position):
        self.slider2.setValue(self.slider2.maximum() - position)

def main():
        app = QApplication(sys.argv)
        w = MyWindow()
        w.show()
        app.exec_()
        sys.exit(0)

if __name__ == "__main__":
    main()

使用python运行代码时没有错误:

python myexample.py

仅当我在 IPython(包括笔记本或 qtconsole 或常规 ipython 终端)中运行代码时才会发生此错误。

更新:我的主要问题是我无法快速轻松地再次运行该应用程序。如果我再次尝试运行我的代码,我会得到:

RuntimeError: A QApplication instance already exists.

这扼杀了 IPython 的快速、交互性 :(

【问题讨论】:

    标签: exception pyqt4 exit ipython pyside


    【解决方案1】:

    感谢 ipython-users 邮件列表中的 Matthias BUSSONNIER。

    当我关闭正在运行的演示应用程序的窗口时,我看到了这个错误: 发生异常,使用 %tb 查看完整的回溯。 系统退出:0

    只是不要使用 sys.exit(0),因为您没有退出 python,但仍在运行 IPython。

    如果您希望从(真实)命令行运行您的应用程序并获得返回状态,请将其添加回来。

    如果我再次尝试执行我的代码,我会得到:
    RuntimeError: QApplication 实例已经存在。

    这是他们“不会修复”的 PySide 错误,因为他们不认为这是一个错误。

    https://github.com/ipython/ipython/issues/1124)
    http://bugs.pyside.org/show_bug.cgi?id=855

    QApplication 只能有一个实例,退出应用程序是 显然没有足够的理由删除 对象...

    您可以从上述问题中使用此代码:

    app=QtGui.QApplication.instance() # checks if QApplication already exists 
    if not app: # create QApplication if it doesnt exist 
         app = QtGui.QApplication(sys.argv)
    

    这对我目前的需求来说已经足够了。

    【讨论】:

    • 感谢您提供解决此问题的代码。这个问题困扰我很久了。
    • 感谢您提供 QApplication.instance() 提示。我从来不知道它有这种方法。现在,我希望可以在我的应用程序中实现应用程序单实例检查。 :)
    【解决方案2】:

    您需要做的是导致 QApplication 稍后被删除,如下所示:

    app = QApplication(sys.argv)
    app.aboutToQuit.connect(app.deleteLater)
    

    使用此代码,您可以在 IPython 或其他任何地方多次重新运行应用程序,并且每次关闭 qt 应用程序时,该对象都将在 python 中删除。

    【讨论】:

      【解决方案3】:

      sys.exit 只是引发 SystemExit 来终止干扰器。

      ipython 在交互模式下执行脚本时会捕获SysExit,因此这实际上不是错误,但 ipython 的一个特性确实避免了交互式解释器在执行脚本时被关闭,因为这不是你通常的情况想要在交互式会话中。

      【讨论】:

      • 好的。如何解决关闭一次后无法再次运行应用程序的问题?我必须重新启动 iPython 内核才能再次执行我的应用程序。否则,我会得到这个:RuntimeError: A QApplication instance already exists.
      • 这与 Qt 有关。您不能同时运行两个 QApplication。最安全的方法重新启动解释器。我只用 PyQt4 尝试过,如果我在创建新 QApplication 之前删除所有对旧 QApplication 的引用,它似乎可以工作。但通常你不应该在同一个进程中启动另一个 QApplication。
      • 好吧,当我关闭我的应用程序时,我不希望解释器保持它运行或保持对它的引用。所以有些东西坏了。重新启动内核不是一个好的解决方案,因为它会扼杀 iPython 的生产力。
      【解决方案4】:

      根据https://github.com/spyder-ide/spyder/issues/4639

      首先,检查实例是否已经存在,然后分配它,或者创建一个新实例:

      if not QApplication.instance():
          app = QApplication(sys.argv)
      else:
          app = QApplication.instance() 
      

      (此 sn-p 取自 @NotSoBrainy 的答案。)

      那么,在show()方法之后:

      QtWidgets.QApplication.setQuitOnLastWindowClosed(True)
      app.exec_()
      app.quit()
      

      不需要sys.exit()

      这解决了我的问题,完全一样。

      【讨论】:

      • 这与@NotSoBrainy 去年给出的答案基本相同。由于您提供了其他详细信息和参考,因此这是一个有用的贡献。但是,在发布旧问题的新答案时,应该承认相似点和不同点。
      • 好的,知道了。实际上,我是从答案中提供的链接中得到的。无论如何,我会承认的。
      【解决方案5】:

      检查是否已经存在 QApplication 实例,因为当实例已经在运行并且您正在尝试创建新实例时会发生错误。

      if not QtWidgets.QApplication.instance():
          app = QtWidgets.QApplication(sys.argv)
      else:
          app = QtWidgets.QApplication.instance()
      

      【讨论】:

        猜你喜欢
        • 2019-09-19
        • 1970-01-01
        • 2021-10-02
        • 1970-01-01
        • 1970-01-01
        • 2012-05-18
        • 2013-04-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多