导入 matplotlib.pyplot 时嵌入式 python 崩溃

Posted

技术标签:

【中文标题】导入 matplotlib.pyplot 时嵌入式 python 崩溃【英文标题】:Embedded python crashes upon import of matplotlib.pyplot 【发布时间】:2016-07-24 01:13:13 【问题描述】:

我搞砸了,试图构建类似于 IPython/Jupyter 笔记本的东西。我正在使用 QT5 编写我的应用程序,其中大部分与在本机应用程序中“嵌入”Python 有关。

我想出了如何嵌入 python 以及如何允许它执行用户输入的脚本。我希望能够使用绘图库(例如 matplotlib),并在我的应用程序中显示它们的输出。 (事实上​​,我正在尝试做的事情似乎与this question 中描述的非常相似)。

但是,当我尝试使用 import matplotlib.pyplot 导入绘图库时,我的应用程序出现段错误(我尝试调试,但崩溃不在我的代码中,所以我无法从中得到任何明智的结果)。

我用来初始化嵌入式 Python 和运行任意脚本的代码显示在这个问题的底部。

我可以很好地导入其他库(例如sysnumpy)。我可以导入matplotlib 很好。但是当我尝试导入matplotlib.pyplot 时,它会出现段错误。

有人有什么建议吗?

编辑: 我已经确定原因(出于某种原因)在于我使用 QT。当我编译一个导入 matplotlib 的简单 C 或 C++ 程序时,它确实 not segfault...

我的代码:

#include "pythoninteractor.h"

#include <QString>
#include <Python.h>
#include <string>
#include <QList>

PythonInteractor::PythonInteractor()
 
    this->pyOutput_redir =
"import sys\n\
class CatchOutErr:\n\
    def __init__(self):\n\
        self.value = ''\n\
    def write(self, txt):\n\
        self.value += txt\n\
catchOutErr = CatchOutErr()\n\
sys.stdout = catchOutErr\n\
sys.stderr = catchOutErr\n\
"; //this is python code to redirect stdouts/stderr


    QString paths[] = "",
                       "/home/tcpie/anaconda3/lib/python35.zip",
                       "/home/tcpie/anaconda3/lib/python3.5",
                       "/home/tcpie/anaconda3/lib/python3.5/plat-linux",
                       "/home/tcpie/anaconda3/lib/python3.5/lib-dynload",
                       "/home/tcpie/anaconda3/lib/python3.5/site-packages",;

    Py_SetProgramName(L"qt-notepad-tut");
    Py_Initialize();

    PyObject *pModule = PyImport_AddModule("__main__"); //create main module
    PyRun_SimpleString(this->pyOutput_redir.toStdString().c_str()); //invoke code to redirect

    PyObject *sys_path;
    PyObject *path;

    sys_path = PySys_GetObject("path");
    if (sys_path == NULL)
        return;

    PySequence_DelSlice(sys_path, 0, PySequence_Length(sys_path));
    for (size_t i = 0; i < sizeof(paths) / sizeof(QString); i++) 
        path = PyUnicode_FromString(paths[i].toStdString().c_str());

        if (path == NULL)
            continue;

        if (PyList_Append(sys_path, path) < 0)
            continue;
    


QString PythonInteractor::run_script(QString script)

    QString ret = "";
    PyObject *pModule = PyImport_AddModule("__main__");
    PyRun_SimpleString(script.toStdString().c_str());
    PyErr_Print(); //make python print any errors

    PyObject *catcher = PyObject_GetAttrString(pModule,"catchOutErr"); //get our catchOutErr created above

    if (catcher == NULL) 
        Py_Finalize();
        return ret;
    

    PyObject *output = PyObject_GetAttrString(catcher,"value"); //get the stdout and stderr from our catchOutErr object

    if (output == NULL) 
        return ret;
    

    ret = QString(PyUnicode_AsUTF8(output));
    return ret;

【问题讨论】:

为什么要尝试嵌入 Python? 我想看看我是否可以在原生应用程序中制作类似于 IPython 笔记本的东西。 我怀疑这是否有意义(Qt 非常好) 这是什么意思? matplotlib.pyplot 可能不是一个好主意。如果我没记错的话,它会尝试创建自己的窗口。后端可能应该是 AggCairoSvg' (matplotlib.use('Svg')),即非图形化以生成 jpg、png 或 svg。 【参考方案1】:

这次崩溃的原因原来是QT版本之间的冲突。

首先,可以使用以下最小代码重现该问题。在 main.h 中注释掉“Q_OBJECT”行可以防止在所有情况下发生崩溃。

文件 main.h:

#ifndef MAIN_H
#define MAIN_H

#include <QMainWindow>

class test : public QMainWindow

    Q_OBJECT // Commenting out this line prevents the crash
;

#endif // MAIN_H

文件 main.cpp:

#include <Python.h>
#include "main.h"

int main()

    Py_Initialize();
    PyRun_SimpleString("import matplotlib.pyplot as plt");    
    PyRun_SimpleString("print('If we are here, we did not crash')");

    Py_Finalize();
    return 0;

我正在通过 Anaconda 运行 Python3。但是,我已经通过我的包管理器安装了 QT5(在我的例子中:Ubuntu 上的 apt-get)。我怀疑问题出在我的 Anaconda 安装的 matplotlib 使用的 QT5 版本与我通过包管理器安装的不同。

修复很简单:通过我的包管理器安装 matplotlib 修复了这个问题! (在我的 Ubuntu 系统上:sudo apt-get install python3-matplotlib

【讨论】:

以上是关于导入 matplotlib.pyplot 时嵌入式 python 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

无法在 virtualenv 中“将 matplotlib.pyplot 作为 plt 导入”

在 Mac OS X 10.12.5 中将 matplotlib.pyplot 导入为 plt 错误

使用 cx_Freeze 导入 matplotlib.pyplot 和 BeautifulSoup

csv读入数据,用julia/matplotlib/pyplot 画矢量图导入word中

python中matplotlib.pyplot的使用示例

服务器上使用matplotlib.pyplot绘图