【Pybind11 C++调用Python并返回结果】

在这里插入图片描述

网上有很多CPP用Pybind11生成pyd的的代码,很少有CPP直接调用python的(想看py调用CPP的看https://www.jianshu.com/p/9619f8f02891,归纳的很全了)
这里简单介绍一下

首先,如果系统已经有最新的默认python3x64,那么直接使用这个的dll,lib以及环境变量,如果没有设置环境变量,那么自己百度里谷歌一下,因为这好像是一个bug,调用py的dll会搜索python的环境变量;如果没有安装,那么更好,直接下载python3.x 64bit,具体版本可以看Pybind11支持的最高版本,并且设置环境变量(一般安装python会有设置环境变量的勾选)
PS:32bit的自己想办法,什么年代了还用这个呢

然后Pybind11是支持C++11的,我们用VS2019+Win10x64开发

这里其实用python原生的C++api也可以,但是麻烦一点,底层应该都是一样
Pybind11已经帮我们做好了

show me the code!

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/numpy.h>
#include <pybind11/embed.h> // everything needed for embedding

#include <iostream>

namespace py = pybind11;
using namespace std;

//C:\Users\23607\AppData\Local\Programs\Python\Python37\
//https://blog.csdn.net/mvp_Dawn/article/details/102535495
/*python3启动失败 Fatal Python error : initfsencoding: unable to load the file system codec*/
//使用主环境默认版本python和其环境变量以及dll
//Python 3.7.6 (default, Jan  8 2020, 20:23:39) [MSC v.1916 64 bit (AMD64)] :: Anaconda, Inc. on win32

int main() {
    py::scoped_interpreter python;

    py::module sys = py::module::import("sys");
    py::print(sys.attr("path"));

    py::module t = py::module::import("tttt");

    py::object result;
    try 
    {
        result = t.attr("add")(1, 2);
    }
    catch (std::exception& e) 
    {
        cout << "call python transpose failed:" << e.what() << endl;
    }
    auto outArray = result.cast<int>();

    printf("outArray:%d\n", outArray);
/*
//返回值类型python代码
//tttt.py
def add(i, j):
    print("hello,pybind11")
    return i + j
*/

    //返回数组测试,参考:https://blog.csdn.net/u013701860/article/details/109812323
    //py::array_t<float> outArray = result.cast<py::array_t<float>>();

     copy output data
    //py::buffer_info outBuf = outArray.request();
    //float* optr = (float*)outBuf.ptr;

    //float* pOutData=new float[outArray.size()];
    //memcpy(pOutData, optr, outArray.size() * sizeof(float));
    //delete[]pOutData;
   
   //返回数组python代码
   /*
   //python math_test.py
   def transpose(data, perm):
    import numpy as np
    result = np.transpose(data, perm)
    resultn = result.reshape(-1).reshape(result.shape)
    return resultn
    */

    getchar();
    return 0;
}

接下来是喜闻乐见的字符串传递,跨平台的字符串传递是最头疼的事情,懂的都懂,反正就是反复套娃
在这里插入图片描述

python和cpp中文字符串传递:
注意,虽然t.attr(“xxx”)这个函数指针我们可以传入std::string(虽然在vc里这个是支持unicode16扩展编码字符的,包括中文,但是跨平台就不一定了)类型,但是对于std::wstring好像没有办法了,如果有,请告诉我,这里仅作抛砖引玉
我们的思路是过程中全部编码为utf-8风格的unsigned char*(->uint8),传递用int*和numpy

PS:既然已经用了uint8,那么其实我们还可以传递文件类型了,比如图片转化为rgb 的uint8后feed到python的opencv或者tensorflow的tensor等等;
py:

import numpy as np 


def ToBytes(data):
    if type(data) == type('12'):
        if len(data)%2 != 0:
            data += '0'
            # print("add '0' at end,amended: ",end="")
            # print(data)
        return bytes().fromhex(data)
    elif type(data) == type([1,]):
        return bytes(data)
    else:
        print("only 'str' or 'list' is valid!")
        return None  

def process_str(int_np_array):
    arr2 = list(int_np_array)
    bytes_in=ToBytes(arr2)
    _str=bytes_in.decode('utf-8')
    print("input str:",_str)
    _str="now process:"+_str
    bytes = _str.encode(encoding='utf-8', errors = 'strict')
    
    b=[a for a in bytes]
    return b
    

CPP

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/numpy.h>
#include <pybind11/embed.h> // everything needed for embedding

#include <iostream>
#include <windows.h>
//#include "base64.hpp"

namespace py = pybind11;
using namespace std;

//https://blog.csdn.net/wyansai/article/details/50764315
// 当type为CP_ACP时,GBK转化为UNICODE;当type为CP_UTF8时,UTF8转化为UNICODE
wchar_t* trans(const char* ch, int type = 0) //UNICODE==65001,CP_ACP==0
{
    int len = MultiByteToWideChar(type, 0, ch, -1, nullptr, 0);
    wchar_t* str = new wchar_t[len + 1];
    wmemset(str, 0, len + 1);
    MultiByteToWideChar(type, 0, ch, -1, str, len);
    return str;
}
// 当type为CP_ACP时,UNICODE转化为GBK;当type为CP_UTF8时,UNICODE转化为UTF8
char* trans(const wchar_t* wch, int type = 0) {
    int len = WideCharToMultiByte(type, 0, wch, -1, nullptr, 0, nullptr, nullptr);
    char* str = new char[len + 1];
    memset(str, 0, len + 1);
    WideCharToMultiByte(type, 0, wch, -1, str, len, nullptr, nullptr);
    return str;
}

//C:\Users\23607\AppData\Local\Programs\Python\Python37\
//https://blog.csdn.net/mvp_Dawn/article/details/102535495
/*python3启动失败 Fatal Python error : initfsencoding: unable to load the file system codec*/
//使用主环境默认版本python和其环境变量以及dll
//Python 3.7.6 (default, Jan  8 2020, 20:23:39) [MSC v.1916 64 bit (AMD64)] :: Anaconda, Inc. on win32

int main() {
    py::scoped_interpreter python;

    py::module sys = py::module::import("sys");
    py::print(sys.attr("path"));

    py::module t = py::module::import("imouto");

    py::object result;
    try
    {
        auto func = t.attr("process_str");
        string inStr = "imouto is love";//"妹妹就是爱love";

        auto xxb = trans(L"imouto is love爱", 65001);
        auto len = strlen(xxb);//inStr.size();
        const unsigned char* ss = (const unsigned char*)xxb;//(const unsigned char*) (inStr.c_str());
        int* ss_copy = new int[len+1];
        std::copy(ss,ss + len, ss_copy);
        //for (size_t i = 0; i < len; i++)
        //{
        //    printf("%d ", ss_copy[i]);
        //}
        //printf("\n");
        ss_copy[len] = (int)'\0';
        vector<int> inDataShape = { (int)(len + 1) };
        // construct numpy array
        py::array_t<int> npInputArray(inDataShape, ss_copy);

        result = func(npInputArray);
        delete[]ss_copy;
    }
    catch (std::exception& e)
    {
        cout << "call python transpose failed:" << e.what() << endl;
    }


    //返回数组测试,参考:https://blog.csdn.net/u013701860/article/details/109812323
    py::array_t<int> outArray = result.cast<py::array_t<int>>();


    py::buffer_info outBuf = outArray.request();
    int* optr = (int*)outBuf.ptr;

    unsigned char* pOutData = new unsigned char[outArray.size()];
    //memcpy(pOutData, optr, outArray.size() * sizeof(int));

    std::copy(optr, optr+ outArray.size(), pOutData);

    for (size_t i = 0; i < outArray.size(); ++i)
    {
        printf("%d ", pOutData[i]);
    }
    //https://blog.csdn.net/CHYabc123456hh/article/details/109021250
    string strHH;
    strHH.append(reinterpret_cast<const char*>(pOutData));
    auto xxx = trans(strHH.c_str(), 65001);
    auto xxc = trans(xxx);
    //std::wcout.imbue(std::locale("chs"));
    //wcout << xxx << endl;
    cout <<"\nresult:"<< xxc << endl;

    delete[]pOutData;

    //返回数组python代码
    /*
    //python math_test.py
    def transpose(data, perm):
     import numpy as np
     result = np.transpose(data, perm)
     resultn = result.reshape(-1).reshape(result.shape)
     return resultn
     */

    printf("--------end-----------\n");
    getchar();
    return 0;
}

如果没有意外的话传输结果是这样的:
在这里插入图片描述
这里我们cpp端传入一个中文字符串L"imouto is love爱"
python端接收后,处理一下马上返回给cpp端,cpp端解码到中文gbk std::string进行输出!

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值