C++中调用py脚本实践经验

背景介绍

VS+Qt+CPP开发,需要处理docx文档。搜了一下C++的库,收费的用不起,免费的不好用。恰好最近在学python,发现python-docx模块很不错,于是写了脚本,在C++中调用。

第二次调用异常

一开始,脚本调用代码写在一个类成员方法中,如下所示:

#include "Python.h"
class Test{
public:
    void WriteDoc(){
        Py_Initialize();
        PyRun_SimpleString("import sys");
	    PyRun_SimpleString("sys.path.append('./Config/Scripts')"); //脚本所在目录

        // do something
        // ...

        Py_Finalize();
    }
}

int main(){
    Test test;
    test.WriteDoc();
    test.WriteDoc();
    return 0;
}

main函数中执行了两次WriteDoc方法。第一次正常执行,第二次程序异常退出,并提示:(1)Fatal Python Error: Failed to import encoding module;(2)Python runtime state: core initiaized;(3)ModuleNotFoundError: No module named ‘encodings’。

有说法是Py_InitializePy_Finalize同一进程中只能调用一次。于是,将Py_InitializePy_Finalize分别放在了构造函数和析构函数中,问题解决。

#include "Python.h"
class Test{
public:
    Test(){
		Py_Initialize();
		PyRun_SimpleString("import sys");
		PyRun_SimpleString("sys.path.append('./Config/Scripts')");
	}

	~Test(){
		Py_Finalize();
	}

    void WriteDoc(){
        // do something
        // ...
    }
}

int main(){
    Test test;
    test.WriteDoc();
    test.WriteDoc();
    return 0;
}

项目打包后程序闪退

将项目打包,并安装在本人开发所用的计算机上,没有任何问题。但是安装在没有python环境的计算机(如虚拟机)上运行,会闪退。通过打印日志发现,在执行构造函数中Py_Initialize方法时就闪退。多方搜索资料后,说是缺少python运行时环境,要在Py_Initialize之前调用Py_SetPythonHome

Py_SetPythonHome(L"./Config//env");
Py_Initialize();
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./Config/Scripts')");

我将本机安装的Python目录复制到项目文件夹下并改名为env,然后将env的相对路径作为Py_SetPythonHome参数,重新打包后,再次安装在虚拟机中运行,没有问题。

直接复制过来的Python目录下有很多无关内容,为了减少打包文件的大小,只保留DLLs和Lib这两个目录即可。这两个目录下的内容也有很多冗余,可以自行删除。

例如,我写的脚本中只用到了python-docx模块,于是在Lib目录下只保留了collections、encodings(Py_Initialize必须)、importlib、pathlib、re、zipfile文件夹以及所有的.py文件(.py文件也可以根据自行生成的__pycache__下的pyc文件对应保留);而在DLLS目录下只保留了所有的.pyd文件。

删除冗余文件的过程比较繁琐,每删除一部分,就运行一下程序,看相关功能是否能正常执行。最后保留下来的,就是python-docx模块以及Py_Initialize所依赖的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值