`
Joson_Coney
  • 浏览: 54897 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

【转】C++调用Python

 
阅读更多

 (from http://blog.csdn.net/marising/archive/2008/09/12/2917892.aspx, http://blog.csdn.net/marising/archive/2008/09/22/2962322.aspx)

   前两篇都是介绍Python调用C++的,换句话说,就是需要把C++封装成Python可以“理解”的类型。这篇,我打算说一下,C++怎么去调用Python脚本。其实这两者之间是相通的,就是需要可以互操作。按照惯例,先贴代码。


test.cpp


 


view plaincopy to clipboardprint?
  
#include <python2.6/Python.h>  
#include <iostream>  
#include <string>  
void printDict(PyObject* obj) {  
    if (!PyDict_Check(obj))  
        return;  
    PyObject *k, *keys;  
    keys = PyDict_Keys(obj);  
    for (int i = 0; i < PyList_GET_SIZE(keys); i++) {  
        k = PyList_GET_ITEM(keys, i);  
        char* c_name = PyString_AsString(k);  
        printf("%s\n", c_name);  
    }  
}  
int main() {  
    Py_Initialize();  
    if (!Py_IsInitialized())  
        return -1;  
    PyRun_SimpleString("import sys");  
    PyRun_SimpleString("sys.path.append('./')");  
    //导入模块  
    PyObject* pModule = PyImport_ImportModule("testpy");  
    if (!pModule) {  
        printf("Cant open python file!\n");  
        return -1;  
    }  
    //模块的字典列表  
    PyObject* pDict = PyModule_GetDict(pModule);  
    if (!pDict) {  
        printf("Cant find dictionary.\n");  
        return -1;  
    }  
    //打印出来看一下  
    printDict(pDict);  
    //演示函数调用  
    PyObject* pFunHi = PyDict_GetItemString(pDict, "sayhi");  
    PyObject_CallFunction(pFunHi, "s", "lhb");  
    Py_DECREF(pFunHi);  
    //演示构造一个Python对象,并调用Class的方法  
    //获取Second类  
    PyObject* pClassSecond = PyDict_GetItemString(pDict, "Second");  
    if (!pClassSecond) {  
        printf("Cant find second class.\n");  
        return -1;  
    }  
    //获取Person类  
    PyObject* pClassPerson = PyDict_GetItemString(pDict, "Person");  
    if (!pClassPerson) {  
        printf("Cant find person class.\n");  
        return -1;  
    }  
    //构造Second的实例  
    PyObject* pInstanceSecond = PyInstance_New(pClassSecond, NULL, NULL);  
    if (!pInstanceSecond) {  
        printf("Cant create second instance.\n");  
        return -1;  
    }  
    //构造Person的实例  
    PyObject* pInstancePerson = PyInstance_New(pClassPerson, NULL, NULL);  
    if (!pInstancePerson) {  
        printf("Cant find person instance.\n");  
        return -1;  
    }  
    //把person实例传入second的invoke方法  
    PyObject_CallMethod(pInstanceSecond, "invoke", "O", pInstancePerson);  
    //释放  
    Py_DECREF(pInstanceSecond);  
    Py_DECREF(pInstancePerson);  
    Py_DECREF(pClassSecond);  
    Py_DECREF(pClassPerson);  
    Py_DECREF(pModule);  
    Py_Finalize();  
    return 0;  
}  



编译

g++ test.cpp -o test -lpython2.6

testpy.py



view plaincopy to clipboardprint?
#!/usr/bin/python  
# Filename: test.py  
class Person:  
    def sayHi(self):  
        print 'hi'  
class Second:  
    def invoke(self,obj):  
        obj.sayHi()  
def sayhi(name):  
    print 'hi',name;  

 


执行

lhb@localhost:~/maplib/clib/pyc/invokepy$ ./test 
sayhi
__builtins__
__file__
__package__
Person
Second
__name__
__doc__
hi lhb
hi

我简单解释一下

  • 这个例子演示了,创建python中Person类的实例,并作为参数调用Second的方法。
  • Py_Initialize()和 Py_Finalize()是初始和销毁Python解释器
  • PyRun_SimpleString( "import sys" )导入sys,接着设置py文件的路径PyRun_SimpleString( "sys.path.append('./')" )
  • 导入模块PyImport_ImportModule( "testpy" ),就是testpy.py模块。
  • 获取模块字典列表,PyModule_GetDict(pModule),可以打印出来看一下如 void  printDict(PyObject* obj)函数
  • 从字典中获取类的类型 PyDict_GetItemString(pDict, "Second" ),如函数也是这样获取的
  • 创造类的实例 PyInstance_New(pClassSecond,NULL,NULL)
  • 调用实例的方法PyObject_CallMethod(pInstanceSecond, "invoke" , "O" ,pInstancePerson)

整个流程就是这样的,并不复杂,如果要进一步研究可以参考:http://www.python.org/doc/

比较特殊的是调用Python函数时,参数的传递,就是c++的类型,怎么转换成Python的类型;另外一个问题是,Python函数的返回值,怎么转换成C++中的类型。
C++转换成Python类型,Py_BuildValue()
http://www.python.org/doc/1.5.2p2/ext/buildValue.html

  1. PyObject* pArgs=PyTuple_New( 1 ); //有几个参数,就是几
  2. PyTuple_SetItem(pArgs, 0 ,Py_BuildValue( "i" , 3 ));  //初始第一个参数,数据类型是i,就是int,值是 3

返回值转换如,PyArg_ParseTuple,请参考
http://www.python.org/doc/1.5.2p2/ext/parseTuple.html


   其实,C++调用Python有两种方式,我前面介绍了第一种方式:通过找到Python模块,类,方法,构造参数来调用。第二中方式,就是通过构造出一个Python的脚本,用python引擎来执行。第一种方式可能更为优雅,符合大多数的反射调用的特点。(我在以前的一个项目中,实现了c#的反射机制,c#调用Com+,c#调用javascript脚本等)。

  还有一个问题,两种语言互相调用的时候,需要做数据结构(如基本类型,字符串,整数类型等,以及自定义的类等类型)间的转换,共享内存中的一个对象。比如,如何将C++的对象实例传入python中,并在python中使用。c++和python并不在一个进程中,因此可以使用boost的shared_ptr来实现。
   下面这个例子,主要是演示了,c++调用python,可以在c++中形成一个python脚本,然后利用PyRun_SimpleString调用;并且,构造一个c++的对象,传入到python中,并在python的脚本中调用其函数。



#include <boost/python.hpp>
#include <iostream>
using namespace boost::python;
class World
{
public:
      void set(std::string msg) { this->msg = msg; }
      std::string greet() { return msg; }
      std::string msg;
};
typedef boost::shared_ptr < World > world_ptr;
BOOST_PYTHON_MODULE(hello)
{
      class_ <World>("World")
          .def("greet", &World::greet)
          .def("set", &World::set)
      ;
      register_ptr_to_python <world_ptr>();
}
int main(int argc, char *argv[])
{
    
    Py_Initialize();
    world_ptr worldObjectPtr (new World);
    worldObjectPtr->set("Hello from C++!");
    try 
    {        
        inithello();
        PyRun_SimpleString("import hello");
        
        object module(handle <>(borrowed(PyImport_AddModule("__main__"))));
        object dictionary = module.attr("__dict__");
        dictionary["pyWorldObjectPtr"] = worldObjectPtr;
        PyRun_SimpleString("pyWorldObjectPtr.set('Hello from Python!')");
    } 
    catch (error_already_set) 
    {
        PyErr_Print();
    }
    std::cout << "worldObjectPtr->greet(): " << worldObjectPtr->greet() <<std::endl;
    Py_Finalize();
    return 0;
}
 
 



 

分享到:
评论

相关推荐

    C++调用Python并传参

    C#调用C++,C++调用Python并传参,包括C++向python传递图片数据,C++向python传递组数据,C++向python传递字符串数据,C++向python传递结构体数据,C++初始化python类数据并调用方法,实际案例,能直接运行,需要安装...

    C++调用Python脚本

    完整的C++调用Python脚本源码,包含参数传递和函数返回值处理等,且解决传递中文参数出现乱码等问题

    c++调用Python函数(并返回数据).zip

    使用c++调用Python中的函数并返回数据,部分代码参考自网络。

    C++调用PYthon脚本(例程)

    本资源为一个完整工程,功能是实现使用C++在执行过程中调用Python脚本,内附VS嵌入Python环境的流程

    C++调用python文件

    C++和Python是开发过程中比较常用的两种语言,实现两者之间的调用能够很好的发挥两种语言的优势。该资源C++调用Python过程的简单示例。

    C++调用python实例

    c++调用Python实例,测试通过可以运行,实现了多个整数参数之间的传递,实现多个list传递。我博客有对应文章讲解

    c++调用python【源码】

    C++调用Python的代码,比较通用,方便调用。

    C++调用python脚本

    C++调用python脚本

    C++调用python demo

    写了一个C++调用python的小代码,调用python的流程有点繁琐,但是借机可以理解python的机理和调用过程,欢迎下载!

    C++调用python,免安装python环境运行

    C++调用python的示例工程(免安装python环境),里面包含使用说明的文档描述等。

    C++调用python函数

    C++调用python发邮件的函数,一个简单实例,注释很详细,其中要注意字符编码是utf-8,程序中不能有中文字符

    C++调用Python3

    C++调用Python3的实例程序,平台Centos7,CLion工程文件。

    C++项目+使用GSL+C++调用Python

    项目脉络清晰,条理分明,包含编译好的GSL 库,调用GSL和C++调用Python的源码。文件树为: . ─app_test │ ├─TEMP_TestGSL │ └─TEMP_TestPython ├─LibGSL │ ├─example │ └─gexport ├─LibPython │ ...

    不安装Python的情况下用C++调用Python

    想在不安装python的情况下调用它,网上说的方法都不太详细,就连官方给的chm文件也没提及怎么配置,摸索了下,找到了简单调用的办法,文章在这里 https://blog.csdn.net/sunnyloves/article/details/45602423

    C++调用Python3函数与类的实例代码

    Vs2015 - C++调用Python3函数与类的实例代码,具体可查看https://blog.csdn.net/automoblie0/article/details/102461477

    C++调用Python Miniconda虚拟环境

    实现C++调用Python中的带参数函数,Python环境为miniconda虚拟环境,可以随着应用程序一起打包发布,使得集成了Python的Qt应用程序更方便部署。

    C_Invoke_Python.rar_C++调用Python_DEMO

    C++ 调用Python发邮件 演示匿名管道 接管标准输入与输出C++ calling Python e-mail demo anonymous pipe to take over the standard input and output

    基于C++和Python混合编程的WORD文档操作方法1

    摘要:介绍了基于C++和Python混合语言编程的WORD文档操作技术及其实现,针对C++开发的原系统对 WORD 文档操作不方便的问题,利用 Python脚本

Global site tag (gtag.js) - Google Analytics