python - PyInstaller 打包的应用程序在控制台模式下工作正常,在窗口模式下崩溃

标签 python qt pyqt pyside pyinstaller

我正在使用 Python 和 PySide 构建一个相当复杂的应用程序。发布的日子终于临近了,所以我想将这个应用程序构建为一个 exe。

但是,我手上有一个奇怪的问题。我过去使用过 PyInstaller(顺便说一下使用版本 2),但从未发生过这种情况。

基本上,当我使用 --console 标志构建应用程序时,它工作正常 - 但它会打开控制台窗口。当我使用窗口标志 (-w) 构建应用程序时,它无法正常工作。它开始和一切,但有所有这些奇怪的故障。例如,加载文本文件通常会引发 BadFileDescriptor 错误(在控制台模式下不会发生),并且应用程序会在执行特定任务后崩溃。更糟糕的是,该任务是一个循环,第一次执行良好,但当它再次开始工作时,它就崩溃了。

当我查看小型转储文件时,发现一些关于 QtGui4.dll 文件的内存访问冲突的错误。同样,这不会发生在控制台模式下。

有人有什么想法吗?

最佳答案

BadFileDescriptor 错误和随之而来的内存访问冲突是由于窗口模式下应用程序的stdout 是固定大小的缓冲区这一事实引起的。 因此,如果您直接使用 printsys.stdout 写入 stdout,一段时间后您会看到这些错误。

您可以通过以下方式解决此问题:

  1. 删除/注释掉关于stdout的文字
  2. 使用日志记录而不是打印到标准输出
  3. 在您的应用程序开始执行时重定向 stdout。这是需要更改较少代码的解决方案,尽管我认为将调试语句移动到 logging 将是更好的选择。

要重定向 stdout,您可以使用这种代码:

import sys
import tempfile
sys.stdout = tempfile.TemporaryFile()
sys.stderr = tempfile.TemporaryFile()

就在执行你的程序之前。您还可以使用一些自定义对象将输出放入“日志”文件或其他文件中,重要的是输出不应填充固定大小的缓冲区。

例如,您可以做这样的事情来利用 logging 模块而无需更改太多代码:

import sys
import logging

debug_logger = logging.getLogger('debug')
debug_logger.write = debug_logger.debug    #consider all prints as debug information
debug_logger.flush = lambda: None   # this may be called when printing
#debug_logger.setLevel(logging.DEBUG)      #activate debug logger output
sys.stdout = debug_logger

这种方法的缺点是 print 对每一行执行更多的 stdout.write 调用:

>>> print 'test'
DEBUG:debug:test
DEBUG:debug:

如果您愿意,您可以编写一个真正的 write 函数来避免这种行为,该函数仅使用“完整行”调用 the_logger.debug

无论如何,我认为这些解决方案应该只是临时的,并且只能在将 print 移植到对 logging.debug 的调用之前使用。

(显然记录器应该写入文件而不是 stdout 以避免错误。)

关于python - PyInstaller 打包的应用程序在控制台模式下工作正常,在窗口模式下崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13429924/

相关文章:

python - 将 PyQT/PySide 小部件绑定(bind)到 Python 中的局部变量

python - API View 中的 Django Rest 框架更新方法以更改 db json 中的值

python - 二维数组中元素比较的算法

c++ - 如何使 QLabel 自动换行?

c++ - 不能使用 C 库(函数)

python - 如何跨线程发送无信号?

python - PyQt 类是否继承自对象?

python - Pygame - 除非在整个跳跃过程中按住跳跃按钮,否则玩家不会跳跃

python - 可能的子字符串列表,其中字母按字母顺序排列。递归地

Qt 应用程序。在 Mac/XP/Vista/Windows 7 上部署 : Any common access directory to put the License File?