C++中如何只加载一次python脚本,然后可以调用python,只为减少时间

在 C++ 中只加载一次 Python 脚本,然后多次调用 Python 函数,可以通过使用 Python/C API 来实现。这种方法不仅可以减少每次调用 Python 函数时的开销,还能使得 Python 脚本中的状态保持一致。

下面是一个详细的示例,展示如何在 C++ 中加载一次 Python 脚本并多次调用 Python 函数。

步骤

  1. 初始化 Python 解释器:使用 Py_Initialize() 函数。
  2. 加载 Python 脚本:使用 PyRun_SimpleString() 函数或 PyObject 系列函数。
  3. 获取 Python 函数:使用 PyObject_GetAttrString() 函数。
  4. 调用 Python 函数:使用 PyObject_CallObject() 函数。
  5. 清理资源:在程序结束时调用 Py_Finalize() 释放资源。

示例代码

假设有一个名为 script.py 的 Python 脚本,内容如下:

python
# script.py def add(a, b): return a + b def multiply(a, b): return a * b

下面是 C++ 代码示例,展示如何只加载一次 script.py 脚本,然后多次调用其中的 addmultiply 函数。

cpp
#include <Python.h> #include <iostream> // 初始化 Python 解释器 void initializePython() { Py_Initialize(); } // 加载 Python 脚本并获取模块和函数对象 PyObject* loadPythonScript(const char* script_name, const char* func_name) { // 加载 Python 文件名(不带 .py 后缀) PyObject* pName = PyUnicode_DecodeFSDefault(script_name); if (!pName) { PyErr_Print(); std::cerr << "Error: unable to decode script name" << std::endl; return nullptr; } // 导入模块 PyObject* pModule = PyImport_Import(pName); Py_DECREF(pName); if (!pModule) { PyErr_Print(); std::cerr << "Error: unable to import module" << std::endl; return nullptr; } // 获取函数对象 PyObject* pFunc = PyObject_GetAttrString(pModule, func_name); if (!pFunc || !PyCallable_Check(pFunc)) { if (PyErr_Occurred()) PyErr_Print(); std::cerr << "Error: function not found or not callable" << std::endl; Py_XDECREF(pFunc); Py_DECREF(pModule); return nullptr; } // 函数对象引用计数+1,返回函数对象 Py_INCREF(pFunc); Py_DECREF(pModule); // 释放模块引用 return pFunc; } // 调用 Python 函数 PyObject* callPythonFunction(PyObject* pFunc, int a, int b) { PyObject* pArgs = PyTuple_Pack(2, PyLong_FromLong(a), PyLong_FromLong(b)); PyObject* pValue = PyObject_CallObject(pFunc, pArgs); Py_DECREF(pArgs); // 释放参数元组引用 if (!pValue) { PyErr_Print(); std::cerr << "Error: function call failed" << std::endl; return nullptr; } return pValue; } // 结束 Python 解释器 void finalizePython() { Py_Finalize(); } int main() { // 初始化 Python 解释器 initializePython(); // 加载 Python 脚本中的函数 PyObject* pAddFunc = loadPythonScript("script", "add"); PyObject* pMultiplyFunc = loadPythonScript("script", "multiply"); if (!pAddFunc || !pMultiplyFunc) { std::cerr << "Error: could not load Python functions" << std::endl; finalizePython(); return 1; } // 调用 Python 函数 PyObject* pResult = callPythonFunction(pAddFunc, 2, 3); if (pResult) { std::cout << "Add result: " << PyLong_AsLong(pResult) << std::endl; Py_DECREF(pResult); // 释放结果对象引用 } pResult = callPythonFunction(pMultiplyFunc, 2, 3); if (pResult) { std::cout << "Multiply result: " << PyLong_AsLong(pResult) << std::endl; Py_DECREF(pResult); // 释放结果对象引用 } // 释放函数对象引用 Py_DECREF(pAddFunc); Py_DECREF(pMultiplyFunc); // 结束 Python 解释器 finalizePython(); return 0; }

代码解释

  1. 初始化 Python 解释器

    cpp
    void initializePython() { Py_Initialize(); }
  2. 加载 Python 脚本并获取模块和函数对象

    cpp
    PyObject* loadPythonScript(const char* script_name, const char* func_name) { PyObject* pName = PyUnicode_DecodeFSDefault(script_name); PyObject* pModule = PyImport_Import(pName); Py_DECREF(pName); PyObject* pFunc = PyObject_GetAttrString(pModule, func_name); if (!pFunc || !PyCallable_Check(pFunc)) { PyErr_Print(); Py_XDECREF(pFunc); Py_DECREF(pModule); return nullptr; } Py_INCREF(pFunc); Py_DECREF(pModule); return pFunc; }
  3. 调用 Python 函数

    cpp
    PyObject* callPythonFunction(PyObject* pFunc, int a, int b) { PyObject* pArgs = PyTuple_Pack(2, PyLong_FromLong(a), PyLong_FromLong(b)); PyObject* pValue = PyObject_CallObject(pFunc, pArgs); Py_DECREF(pArgs); if (!pValue) { PyErr_Print(); return nullptr; } return pValue; }
  4. 结束 Python 解释器

    cpp
    void finalizePython() { Py_Finalize(); }
  5. main 函数中

    • 初始化 Python 解释器。
    • 加载 Python 脚本中的 addmultiply 函数。
    • 调用 Python 函数并输出结果。
    • 释放 Python 函数对象和解释器资源。

这种方法通过一次加载 Python 脚本,并多次调用其中的函数,有效地减少了每次调用的开销。