c/c++程序如何调用python函数

  为了提高开发效率,扩展开发程序的功能,我们经常会在我们的linux c/c++进程里调用外部脚本, 例如lua、python,下面,介绍下如何在自己的linux c/c++代码里调用python脚本里的函数和类,并且将python库集成到我们自己的进程目录里,这样就不依赖系统环境是否存在python及其版本要求。

  1、编译python库

    我们首先可以从python官网下载需要的python版本,下载链接  https://www.python.org/ftp/python/2.7.5/Python-2.7.5.tgz

    这里下载的版本是python2.7.5, 下载后解压,解压命令:tar -xvf Python-2.7.5.tgz

    进入解压目录,配置编译选项,可以通过./configure -h 查询配置选项,这里执行如下命令, --enable-shared保证生成动态库

    ./configure --prefix=/home/local --enable-optimizations --enable-shared

    执行上述命令后, 就会在/home/local目录下生成python成果物

      2、构建工程目录

    将上面成果物里的lib目录和头文件目录拷贝到我们的工程中,如下图:

    编译命令g++ -g main.cpp -L./lib -lpython2.7 -Wl,-rpath,./lib -std=c++11  -o prj, 这里需要链接libpython2.7.so,生成名为prj的可执行程序。执行./prj,会有如下输出: 

    

     注意:其实程序运行时,加载的libpython2.7.so依赖的python模块路径是/home/local下面的lib/python2.7/lib-dynload文件夹,而不是当前进程目录的python2.7, 我们需要添加环境变量,指定加载模块路径,可以设置

      export PYTHONPATH=./lib/python2.7/lib-dynload/

    也可以设置export PYTHONHOME=./, 这个优先级小于PYTHONPATH

其中my.py代码如下:

#!/usr/bin/python
import json
class ClassA:
    def HandleData(self, strJson):
        print "method param:",strJson
        jsonRoot = json.loads(strJson)
        jsonRet={}
        jsonRet["json1"]=jsonRoot
        jsonRet["json2"]="hero"
        a = json.dumps(jsonRet, indent=4)
        return a

def HandleData(strJson1, strJson2):
    print "func param1:",strJson1," param2:", strJson2  
    json1 = json.loads(strJson1)
    json2 = json.loads(strJson2)
    jsonRet={}
    jsonRet["json1"]=json1
    jsonRet["json2"]=json2
    a = json.dumps(jsonRet, indent=4)
    return a

main.cpp代码如下

#include "python2.7/Python.h"
#include "python2.7/frameobject.h"
#include <string>

void fetchPythonError()
{
    PyObject* type = nullptr;
    PyObject* value= nullptr;
    PyObject* traceback = nullptr;
    PyErr_Fetch(&type, &value, &traceback);
    if (type)
    {
        printf("type: %s\n", PyExceptionClass_Name(type));
    }
    if (value)
    {
        PyObject* line = PyObject_Str(value);
        if (line)
        {
            printf("value: %s\n", PyString_AsString(line));
        }
    }
    if (traceback)
    {
        for (PyTracebackObject* tb = (PyTracebackObject*)traceback;
            tb != nullptr && tb->tb_frame != nullptr && tb->tb_frame->f_code != nullptr
            && tb->tb_frame->f_code->co_filename != nullptr
            && tb->tb_frame->f_code->co_name != nullptr;
            tb = tb->tb_next)
        {
            printf("File %s, line %d, in %s\n",
            PyString_AsString(tb->tb_frame->f_code->co_filename), tb->tb_lineno, PyString_AsString(tb->tb_frame->f_code->co_name));
        }
    }
}

int main(int argc, char** argv)
{
    Py_Initialize(); //虚拟机初始化
    if (!Py_IsInitialized())
    {
        fetchPythonError();
        printf("Py_Initialize failed\n");
        return -1;
    }
    PyEval_InitThreads();
    //PyEval_ReleaseThread(PyThreadState_GET());

    PyGILState_STATE state = PyGILState_Ensure();
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append(\'./\')"); //加载当前路径下的所有py模块
    PyGILState_Release(state);

    PyObject* pModule = PyImport_ImportModule("my");//导入模块
    if (pModule == nullptr)
    {
        fetchPythonError();
        printf("PyImport_ImportModule failed\n");
        return -1;
    }
    
    PyObject* pDict = PyModule_GetDict(pModule);//模块的字典列表
    if (pDict == nullptr)
    {
        fetchPythonError();
        printf("PyModule_GetDict failed\n");
        Py_DECREF(pModule);
        return -1;
    }

    /*调用功能函数*/
    PyObject* pFunc = PyDict_GetItemString(pDict, "HandleData"); 

    if (pFunc == nullptr || !PyCallable_Check(pFunc))
    {
        fetchPythonError();
        printf("PyDict_GetItemString failed,func: %s\n", "HandleData");
        Py_DECREF(pDict);
        Py_DECREF(pModule);
        return -1;
    }
    std::string param1 = "{\"name\":\"hello\"}";
    std::string param2 = "{\"xing\":\"world\"}";
    PyObject* pReturn = PyObject_CallFunction(pFunc,"ss", param1.c_str(), param2.c_str());
    char* pszResult = nullptr;
    PyArg_Parse(pReturn,"s", &pszResult);
    if (pszResult == nullptr)
    {
        return -1;
    }
    printf("func return :\n %s\n", pszResult);
    Py_DECREF(pReturn);
    Py_DECREF(pFunc);

    /*调用类成员method*/
    PyObject* pClass = PyDict_GetItemString(pDict, "ClassA");
    if (pClass == nullptr)
    {
        fetchPythonError();
        printf("PyDict_GetItemString failed,class:%s\n", "ClassA");
        Py_DECREF(pDict);
        Py_DECREF(pModule);
        return -1;
    }
    PyObject* pInstance = PyInstance_New(pClass, NULL, NULL);
    if (pInstance == nullptr)
    {
        fetchPythonError();
        printf("PyInstance_New failed,class:%s\n", "ClassA");
        Py_DECREF(pDict);
        Py_DECREF(pModule);
        return -1;
    }
    pReturn = PyObject_CallMethod(pInstance, "HandleData","s", param1.c_str());
    PyArg_Parse(pReturn, "s", &pszResult);
    if (pszResult == nullptr)
    {
        return -1;
    }

    printf("func return :\n %s\n", pszResult);

    Py_DECREF(pReturn);
    Py_DECREF(pInstance);
    Py_DECREF(pClass);

    Py_DECREF(pDict);
    Py_DECREF(pModule);
    Py_Finalize();//关闭解释器
    return 0;
}

 

  

 

posted @ 2023-04-29 21:10  ho966  阅读(556)  评论(0编辑  收藏  举报