(pybind)c++调用python/python调用c++

pybind通常是使用c++调用python文件,创建一个名为test_basic.py的文件,下面叙述调用步骤:

1.c++调用python:

def test_main():
    print("hello python.")
    
def test_func2(a):
    print(type(a))
    a.print()

2.python调用c++,其实原理就是c++调用python再hook回去cpp代码,传给python的参数是一个对象(可以是指针,对象也可以),对象内部包含这cpp的函数,在python层的方法里面,调用cpp的方法即可。

#include <pybind11/pybind11.h>
#include <pybind11/functional.h>

#include <pybind11/embed.h>

#define STRINGIFY(x) #x
#define MACRO_STRINGIFY(x) STRINGIFY(x)

class A
{
public:
    A() {}
    double a;

    void print();
};

void A::print()
{

    printf("hello A.\n");
}

namespace py = pybind11;

PYBIND11_EMBEDDED_MODULE(embeded, module)
{
    py::class_<A> a(module, "A");
    a.def("print", &A::print);
}

int main()
{
    py::scoped_interpreter python;

    auto test = py::module::import("tests.test_basic");
    auto embeded = py::module::import("embeded");
    // auto func = test.attr("test_main");
    py::object result;
    // result = func();
    auto func2 = test.attr("test_func2");
    // auto a = new A();
    auto a = A();
    // auto func_a = []()
    // { printf("hello anonymous function.\n"); };
    a.a = 1.0;
    result = func2(a);
}```

<think>我们使用pybind11将C++Python进行绑定,使得C++可以调用Python类。主要步骤包括: 1. 初始化Python解释器。 2. 导入Python模块并获取类对象。 3. 创建该类的实例。 4. 调用实例的方法或访问属性。 下面是一个详细的步骤说明和代码示例。 ### 步骤详解 1. **初始化Python解释器**:在C++程序中,需要先初始化Python解释器,并确保在程序结束前关闭解释器。 2. **导入模块**:使用`pybind11::module_::import`导入目标Python模块。 3. **获取类对象**:从模块中获取类的对象(通常通过`attr`方法)。 4. **创建实例**:通过调用类对象(即调用其构造函数)来创建实例。 5. **调用方法或访问属性**:使用实例的`attr`方法获取方法(然后调用)或属性。 ### 示例代码 假设有一个Python类定义在`example.py`中: ```python # example.py class MyClass: def __init__(self, value): self.value = value def get_value(self): return self.value def set_value(self, value): self.value = value ``` 在C++调用这个类的步骤: ```cpp #include <pybind11/embed.h> // 包含嵌入头文件 namespace py = pybind11; int main() { // 1. 初始化Python解释器 py::scoped_interpreter guard{}; // 2. 导入模块 py::module_ example = py::module_::import("example"); // 3. 获取类对象 py::object MyClass = example.attr("MyClass"); // 4. 创建实例,传入构造参数 py::object obj = MyClass(123); // 5. 调用方法 // 5.1 调用无参方法 int value = obj.attr("get_value")().cast<int>(); std::cout << "Initial value: " << value << std::endl; // 5.2 调用带参方法 obj.attr("set_value")(456); value = obj.attr("get_value")().cast<int>(); std::cout << "After set_value: " << value << std::endl; // 5.3 访问属性(注意:直接访问属性用attr,修改属性用attr("属性名") = 值) int value_attr = obj.attr("value").cast<int>(); std::cout << "Direct attribute access: " << value_attr << std::endl; obj.attr("value") = 789; value_attr = obj.attr("value").cast<int>(); std::cout << "After direct set: " << value_attr << std::endl; return 0; } ``` ### 注意事项 - **作用域解释器**:使用`py::scoped_interpreter`确保解释器在作用域结束时关闭。 - **GIL锁**:在操作Python对象时,确保持有GIL(全局解释器锁)。`scoped_interpreter`会自动获取,但在多线程中需要手动管理。 - **错误处理**:调用Python函数可能抛出异常,需要使用try-catch捕获`py::error_already_set`。 - **路径设置**:如果Python模块不在当前路径,需要添加模块搜索路径,例如: ```cpp py::module_ sys = py::module_::import("sys"); sys.attr("path").attr("append")("/path/to/module"); ``` ### 编译和运行 编译时需要链接Python库和pybind11。例如,使用CMake: ```cmake find_package(Python COMPONENTS Interpreter Development REQUIRED) find_package(pybind11 REQUIRED) add_executable(example main.cpp) target_link_libraries(example PRIVATE pybind11::embed) ``` §§相关问题§§ 1. 在C++中通过pybind11调用Python类时,如何处理Python抛出的异常? 2. 在多线程环境下,如何安全地使用pybind11调用Python代码? 3. 如何通过pybind11将C++类暴露给Python,实现双向调用? 4. 使用pybind11嵌入Python解释器时,如何正确管理Python模块的导入路径?</think>### C++通过pybind11调用Python类的步骤 使用pybind11在C++调用Python类需要以下关键步骤: #### 1. **环境准备** - 安装pybind11:`pip install pybind11` - 编译带嵌入支持的Python(启用`--enable-shared`) #### 2. **C++调用代码实现** ```cpp #include <pybind11/embed.h> namespace py = pybind11; int main() { // 初始化Python解释器 py::scoped_interpreter guard{}; // 导入Python模块 py::module_ sys = py::module_::import("sys"); sys.attr("path").attr("append")("."); // 添加模块搜索路径 // 导入自定义模块 py::module_ mymodule = py::module_::import("mymodule"); // 获取Python类 py::object PyClass = mymodule.attr("MyPythonClass"); // 创建类实例 py::object instance = PyClass("constructor_arg"); // 调用类方法 py::object result = instance.attr("method_name")(42, "arg2"); // 处理返回值 int cpp_value = result.cast<int>(); std::cout << "Result: " << cpp_value << std::endl; // 访问属性 std::string attr_value = instance.attr("attribute").cast<std::string>(); return 0; } ``` #### 3. **Python模块示例(mymodule.py)** ```python class MyPythonClass: def __init__(self, arg): self.attribute = arg print(f"Constructor called with: {arg}") def method_name(self, num, text): print(f"Method called: {num}, {text}") return num * 2 ``` #### 4. **编译与链接** 使用CMake配置(CMakeLists.txt): ```cmake cmake_minimum_required(VERSION 3.12) project(EmbedPythonExample) find_package(Python COMPONENTS Interpreter Development REQUIRED) find_package(pybind11 REQUIRED) add_executable(main main.cpp) target_link_libraries(main PRIVATE pybind11::embed) ``` #### 5. **关键注意事项** 1. **生命周期管理**: - 使用`py::scoped_interpreter`确保解释器正确初始化和清理 - 保持Python对象引用避免提前释放 2. **类型转换**: - 使用`cast<T>()`转换基本类型 - 复杂对象需自定义类型转换器 3. **异常处理**: ```cpp try { // Python调用代码 } catch (const py::error_already_set &e) { std::cerr << "Python error: " << e.what() << std::endl; } ``` 4. **GIL管理**: - 多线程中手动获取GIL: ```cpp py::gil_scoped_acquire acquire; // Python操作 ``` #### 6. **高级用法** - 继承Python类: ```cpp class CppDerived : public py::object { // 实现Python调用C++类 }; ``` - 回调函数: ```cpp instance.attr("callback") = py::cpp_function([](int arg) { std::cout << "C++ callback: " << arg << std::endl; }); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值