编程笔记

编程笔记

C++:c++中调用Python代码的几种方法
2025-01-29

  • 使用 Python C API
  • 通过 system() 函数调用 Python 脚本
  • 嵌入 Python 解释器
  • 使用第三方库,如 pybind11Boost.Python

建议使用第四种的示例二,比较简单,有其他博客讲解visual studio怎么配置环境。

1. 使用 Python C API

Python 提供了一个 C API,允许在 C/C++ 程序中嵌入 Python 代码。首先需要确保 Python 开发包已经安装。你可以通过 #include <Python.h> 来使用 Python C API。

示例:

#include <Python.h>

int main() {
    // 初始化 Python 解释器
    Py_Initialize();

    // 运行简单的 Python 代码
    PyRun_SimpleString("print('Hello from Python in C++!')");
    
    // 关闭 Python 解释器
    Py_Finalize();
    return 0;
}

编译时,需要链接 Python 库:

g++ my_program.cpp -o my_program -I/usr/include/python3.x -lpython3.x

2. 通过 system() 函数调用 Python 脚本

你可以使用 C++ 的 system() 函数来调用外部 Python 脚本。虽然简单,但这方法不太灵活。

示例:

#include <cstdlib>

int main() {
    // 通过系统命令调用 Python 脚本
    system("python3 my_script.py");
    return 0;
}

3. 嵌入 Python 解释器

嵌入 Python 解释器允许你更灵活地调用 Python 函数和模块。你可以使用 Python C API 调用 Python 函数、传递参数、获取返回值等。

示例:

#include <Python.h>

int main() {
    Py_Initialize();  // 初始化 Python 解释器

    // 导入 Python 模块
    PyObject* pModule = PyImport_ImportModule("math");
    if (pModule != nullptr) {
        // 获取模块中的函数
        PyObject* pFunc = PyObject_GetAttrString(pModule, "sqrt");
        if (pFunc && PyCallable_Check(pFunc)) {
            // 准备调用参数
            PyObject* pArgs = PyTuple_Pack(1, PyFloat_FromDouble(9.0));

            // 调用 Python 函数
            PyObject* pValue = PyObject_CallObject(pFunc, pArgs);
            if (pValue != nullptr) {
                double result = PyFloat_AsDouble(pValue);
                std::cout << "Result of sqrt(9.0) = " << result << std::endl;
                Py_DECREF(pValue);
            }
            Py_DECREF(pArgs);
            Py_DECREF(pFunc);
        }
        Py_DECREF(pModule);
    }
    
    Py_Finalize();  // 关闭 Python 解释器
    return 0;
}

4. 使用 pybind11

pybind11 是一个用于 C++ 和 Python 交互的库,可以轻松地将 Python 代码嵌入 C++,并允许你在 Python 中使用 C++ 代码。

安装 pybind11

pip install pybind11

示例1:

#include <pybind11/embed.h> // 需要包含此头文件

namespace py = pybind11;

int main() {
    py::scoped_interpreter guard{};  // 启动 Python 解释器

    py::exec(R"(
        print("Hello from Python inside C++ using pybind11!")
    )");

    return 0;
}

示例2:

Python 脚本:假设你的 Python 文件 my_script.py 里有一个函数 greet,你想从 C++ 传递一个字符串参数给它,并让它执行。

# my_script.py
def greet(name):
    print(f"Hello, {name}!")

C++ 代码:使用 pybind11 来加载这个 Python 文件,调用 greet 函数并传递参数。

#include <pybind11/embed.h>
#include <iostream>
#include <string>

namespace py = pybind11;

int main() {
    py::scoped_interpreter guard{};  // 初始化 Python 解释器

    try {
        // 导入 Python 脚本
        py::object my_script = py::module_::import("my_script");

        // 从 Python 脚本中获取函数
        py::object greet_func = my_script.attr("greet");

        // 调用函数并传递 C++ 字符串
        std::string name = "ChatGPT";
        greet_func(name);

    } catch (const std::exception &e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }

    return 0;
}

编译并运行:

  • 你需要将 Python 包路径包括在编译中,并链接 Python 库。
  • 例如,使用 g++ 编译:
g++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` my_program.cpp -o my_program `python3-config --ldflags`

关键步骤说明:

  • py::module_::import("my_script"):加载 Python 文件 my_script.py(注意,该文件应该在执行的路径下或 Python 可查找的路径下)。
  • my_script.attr("greet"):获取 Python 中定义的 greet 函数。
  • greet_func(name):调用函数并传递 std::string 参数。

运行时注意:

确保 Python 的文件(my_script.py)和编译的 C++ 程序位于同一目录,或者将 Python 文件的路径添加到 Python 的模块搜索路径中。

示例输出:

Hello, ChatGPT!