python c++ 混合编程_很好的c++和Python混合编程文章

1. 一个有一个参数的例子

python文件

#Filename test2.py

def Hello(s):

print "Hello, world!"

print s

cpp文件

#include

int main()

{

Py_Initialize();

PyObject * pModule = NULL;

PyObject * pFunc = NULL;

PyObject * pArg = NULL;

pModule = PyImport_ImportModule("test2");

pFunc = PyObject_GetAttrString(pModule, "Hello");

pArg = Py_BuildValue("(s)", "function with argument");

PyEval_CallObject(pFunc, pArg);

Py_Finalize();

return 0;

}

注意,参数要以tuple元组形式传入。因为这个函数只要一个参数,所以我们直接使用(s)构造一个元组了。

2. 一个有两个参数的例子

python文件中加入以下代码,一个加函数

def Add(a, b):

print "a+b=", a+b

cpp文件,只改了两行,有注释的那两行

#include

int main()

{

Py_Initialize();

PyObject * pModule = NULL;

PyObject * pFunc = NULL;

PyObject * pArg = NULL;

pModule = PyImport_ImportModule("test2");

pFunc = PyObject_GetAttrString(pModule, "Add");//终于告别hello world了,开始使用新的函数

pArg = Py_BuildValue("(i,i)", 10, 15);//构造一个元组

PyEval_CallObject(pFunc, pArg);

Py_Finalize();

return 0;

}

其它的就类似了。。。基本上,我们知道了怎么在c++中使用python中的函数。接下来学习一下如何使用python中的

class。

附:Py_BuildValue的使用例子,来自python documentation:

Py_BuildValue("") None

Py_BuildValue("i", 123) 123

Py_BuildValue("iii", 123, 456, 789) (123, 456, 789)

Py_BuildValue("s", "hello") 'hello'

Py_BuildValue("ss", "hello", "world") ('hello', 'world')

Py_BuildValue("s#", "hello", 4) 'hell'

Py_BuildValue("()") ()

Py_BuildValue("(i)", 123) (123,)

Py_BuildValue("(ii)", 123, 456) (123, 456)

Py_BuildValue("(i,i)", 123, 456) (123, 456)

Py_BuildValue("[i,i]", 123, 456) [123, 456]

Py_BuildValue("{s:i,s:i}",

"abc", 123, "def", 456) {'abc': 123, 'def': 456}

Py_BuildValue("((ii)(ii)) (ii)",

1, 2, 3, 4, 5, 6) (((1, 2), (3, 4)), (5, 6))

这次主要讲讲怎么把python中的class嵌入到c++中去。

顺便讲讲元组的操作和怎么编译python源代码。

1. 首先讲讲元组的操作

由于参数是通过元组传进去的,所以我们不能老是通过Py_BuildValue这个函数来操作元组,那样太不方便了。

Python提供了元组相关的操作,下面这个例子演示了如何操作。主要是下面几个函数:

//new一个元组,传入size

pArgs = PyTuple_New(argc - 3);

//set元组的直,第一个为元组,第二个为index(从0开始),第三个为value

PyTuple_SetItem(pArgs,0,Py_BuildValue("i",2000) );

PyTuple_SetItem(pArgs,1,Py_BuildValue("i",8) );

来自python doc的一个例子

#include

int

main(int argc, char *argv[])

{

PyObject *pName, *pModule, *pDict, *pFunc;

PyObject *pArgs, *pValue;

int i;

if (argc < 3) {

fprintf(stderr,"Usage: call pythonfile funcname [args]/n");

return 1;

}

Py_Initialize();

pName = PyString_FromString(argv[1]);

/* Error checking of pName left out */

pModule = PyImport_Import(pName);

Py_DECREF(pName);

if (pModule != NULL) {

pFunc = PyObject_GetAttrString(pModule, argv[2]);

/* pFunc is a new reference */

if (pFunc && PyCallable_Check(pFunc)) {

pArgs = PyTuple_New(argc - 3);

for (i = 0; i < argc - 3; ++i) {

pValue = PyInt_FromLong(atoi(argv[i + 3]));

if (!pValue) {

Py_DECREF(pArgs);

Py_DECREF(pModule);

fprintf(stderr, "Cannot convert argument/n");

return 1;

}

/* pValue reference stolen here: */

PyTuple_SetItem(pArgs, i, pValue);

}

pValue = PyObject_CallObject(pFunc, pArgs);

Py_DECREF(pArgs);

if (pValue != NULL) {

printf("Result of call: %ld/n", PyInt_AsLong(pValue));

Py_DECREF(pValue);

}

else {

Py_DECREF(pFunc);

Py_DECREF(pModule);

PyErr_Print();

fprintf(stderr,"Call failed/n");

return 1;

}

}

else {

if (PyErr_Occurred())

PyErr_Print();

fprintf(stderr, "Cannot find function /"%s/"/n", argv[2]);

}

Py_XDECREF(pFunc);

Py_DECREF(pModule);

}

else {

PyErr_Print();

fprintf(stderr, "Failed to load /"%s/"/n", argv[1]);

return 1;

}

Py_Finalize();

return 0;

}

2. class操作

把下面加入到test2.py中去。定义了一个很简单的类,有一个name成员变量,一个printName成员函数

class TestClass:

def __init__(self,name):

self.name = name

def printName(self):

print self.name

cpp文件

#include

int main()

{

Py_Initialize();

PyObject * pModule = NULL;

PyObject * pFunc = NULL;

PyObject * pArg = NULL;

PyObject * pClass = NULL;

PyObject * pObject = NULL;

pModule = PyImport_ImportModule("test2");

pClass = PyObject_GetAttrString(pModule, "TestClass");//得到那个类

pArg = PyTuple_New(1);

PyTuple_SetItem(pArg, 0, Py_BuildValue("s", "Jacky"));

pObject = PyEval_CallObject(pClass, pArg);//生成一个对象,或者叫作实例

pFunc = PyObject_GetAttrString(pObject, "printName");//得到该实例的成员函数

PyEval_CallObject(pFunc, NULL);//执行该实例的成员函数

Py_Finalize();

return 0;

}

没有什么资料,就先写到这里了。下面介绍一下怎么build python25的源代码

3. 编译python源代码

为什么要编译呢?因为没有python25_d.lib!呵呵。顺便可以了解一下代码结构。

解压缩后,有好多目录,其中pcbuild和pcbuild8是我们要的。pcbuild对应着vc7.1的,pcbuild8对应着vc8.0的

因为在用vc7.1,也就是2003了。所以我就说说怎么用2003来编译吧。事实上是从一位牛人那里学来的

阿。看来我只能后来居上了,娃哈哈。我按照他说的试了一下,编译成功!

不过遇到一点小问题,用vc2003打开那个solution的时候,发现作者没有把source code control去掉,郁闷!害的我

们打开的时候一堆messagebox。不过不用管它就好了,一直确定。最后试了一下那个python25_d.lib,没问题。不过记

得把python25_d.dll copy到一个能被找到的目录,比如说c:/windows/system32/下面。python25.dll也在这个目录下

面。over。恩。

坏境python25 + vs2005 (2005真耗资源阿。。。)

有一段时间没写blog了。这几天都在研究怎么封装c++,让python可以用c++的库。在网上发现了boost.python这个好咚咚。不

过在使用过程中碰到一点问题。本文教大家如何把

char const* greet()

{

return "hello, world";

}

封装成python。实际上这是python教程里面的咚咚。

首先下载Boost,www.boost.org。boost.python在boost里面了。在visual studio 2005 command prompt中navigation到

boost/boost_1_34_0/下。记得一定要用visual studio 2005 command prompt这个vs2005带的tools,不要用cmd.exe,否则会

碰到很多错误的。然后就是把bjam.exe拷贝到一个能被找到的目录下,或者直接也拷贝到boost/boost_1_34_0/下即可。然后,

设置python的根目录和python的版本,也可直接把它们加到坏境目录中,那样就不用每次都设置一下。

set PYTHON_ROOT=c:/python25

set PYTHON_VERSION=2.5

接着就可以直接运行了,bjam -sTOOLS=vc-8_0

整个编译过程要很长时间。。。

成功之后,就会有好多个boost_python-vc80-****.dll,.lib的,把他们都拷贝到一个能被系统找到的目录,不妨直接把他们都

扔到c:/windows/system32下。

接着,我们开始编译hello。navigation到boost/boost_1_34_0/libs/python/example/tutorial下,bjam -sTOOLS=vc-8_0运行

,在bin的目录下即会生成hello.pyd。这下就基本成功了,如果没成功的话,check一下上面boost_python的那些dll能否被系

统找到。另外,这里有python25的一个bug。。。我花了很长时间才在python的mail lists中找到了。寒。。。

错误如下所示:

D:/Learn/Python/boost/boost_1_34_0/libs/python/example/tutorial>bjam

Jamroot:17: in modules.load

rule python-extension unknown in module Jamfile/Learn/Python/boost/boost_1_3

4_0/libs/python/example/tutorial>.

D:/Learn/Python/boost/boost_1_34_0/tools/build/v2/build/project.jam:312: in load

-jamfile

D:/Learn/Python/boost/boost_1_34_0/tools/build/v2/build/project.jam:68: in load

D:/Learn/Python/boost/boost_1_34_0/tools/build/v2/build/project.jam:170: in proj

ect.find

D:/Learn/Python/boost/boost_1_34_0/tools/build/v2/build-system.jam:237: in load

D:/Learn/Python/boost/boost_1_34_0/libs/python/example/../../../tools/build/v2/k

ernel/modules.jam:261: in import

D:/Learn/Python/boost/boost_1_34_0/libs/python/example/../../../tools/build/v2/k

ernel/bootstrap.jam:132: in boost-build

D:/Learn/Python/boost/boost_1_34_0/libs/python/example/boost-build.jam:7: in mod

ule scope

解决办法如下:

在boost/boost_1_34_0/tools/build/v2/目录下找到user-config.jam文件,打开在

import toolset : using ;

下面加一行代码:

using python ;

再重新编译一下boost,然后就没问题了。tutorial里面的hello能顺利编译通过。ps.这个问题困扰了我好长时间。。sigh。。

编译成功后会产生一个hello.pyd,在bin的目录下面。

有好多办法测试此hello.pyd是否可以用。

方法一,把它拷贝到python25/dlls下,打开IDLE,

>>> import hello

>>> hello.greet()

'hello, world'

>>>

方法二,直接在当前目录下写一个python文件,然后直接调用hello.pyd即可。总之,hello.pyd就是一个python文件了。。嗯

。操作hello.pyd根其他python文件是一样的。

这样就成功了。

如果碰到如下错误,是因为系统找不到boost_python的dll。强烈建议把他们都扔到system32下!。

>>> import hello

Traceback (most recent call last):

File "", line 1, in

import hello

ImportError: DLL load failed: 找不到指定的模块。

>>>

说明,hello.cpp在boost/boost_1_34_0/libs/python/example/tutorial目录下。里面的内容是:

// Copyright Joel de Guzman 2002-2004. Distributed under the Boost

// Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt

// or copy at http://www.boost.org/LICENSE_1_0.txt)

// Hello World Example from the tutorial

// [Joel de Guzman 10/9/2002]

char const* greet()

{

return "hello, world";

}

#include

#include

using namespace boost::python;

BOOST_PYTHON_MODULE(hello)

{

def("greet", greet);

}

其中

BOOST_PYTHON_MODULE(hello)

{

def("greet", greet);

}

是对greet从c++向python的一个封装声明吧,装换就交给boost了。

先写到这里了。下次再写。。嗯

这次讲讲,如何扩展c++库。通过boost.python把c++库编译成python能够调用的dll。

通过上一次的教程后,大家都应该会使用boost.python了。把c++程序编译成pyd文件。由于c++有很多特性,所以,如果你的程

序用了很多的c++特性的话,那么你必须做很多工作了。像虚拟函数,函数重载,继承,默认值等等。具体如何转化,请参

boost.python的文档了。

这几天尝试着把c++程序库编译成python可调用的dll,不知道为什么一直不可用。。很是郁闷。老是显示如下的错误:

Traceback (most recent call last):

File "", line 1, in

import pydll

ImportError: No module named pydll

意思是说找不到dll。我把dll都copy到python/dlls下了还是不行,而且我确定python的sys.path包含了python/dlls目录了。

很是不解。网上也很难找到资料,google了很长时间找不到有用的资料,好像中文方面的资料很少的。今天尝试了一下google

英文资料,终于有了新的发现:

http://mail.python.org/pipermail/c++-sig/2007-February/011971.html

You are using Python2.5. In this version of Python you have to have

file extension

to be "pyd" - sge.pyd

--

Roman Yakovenko

C++ Python language binding

http://www.language-binding.net/

有人碰到的问题跟我的是一样的。后面那个Roman回答了一下,是文件扩展名的问题!!!为什么不支持dll呢?不解。回去试

了一下把后缀名改了就成功了。。。why???

这是一个非常简单的dll工程。给python提供了一个函数static PyObject* Recognise(PyObject *self, PyObject *args)。

1、不使用boost.python库来直接构建dll

接下来,我们来用C++为Python编写扩展模块(动态链接库),并在Python程序中调用C++开发的扩展功能函数。生成一个取名为

pyUtil的Win32 DLL工程,除了pyUtil.cpp文件以外,从工程中移除所有其它文件,并填入如下的代码:

// pyUtil.cpp

#ifdef PYUTIL_EXPORTS

#define PYUTIL_API __declspec(dllexport)

#else

#define PYUTIL_API __declspec(dllimport)

#endif

#include

#include

#include

BOOL APIENTRY DllMain( HANDLE hModule,

DWORD ul_reason_for_call,

LPVOID lpReserved

)

{

switch (ul_reason_for_call)

{

case DLL_PROCESS_ATTACH:

case DLL_THREAD_ATTACH:

case DLL_THREAD_DETACH:

case DLL_PROCESS_DETACH:

break;

}

return TRUE;

}

std::string Recognise_Img(const std::string url)

{

//返回结果

return "从dll中返回的数据... : " +url;

}

static PyObject* Recognise(PyObject *self, PyObject *args)

{

const char *url;

std::string sts;

if (!PyArg_ParseTuple(args, "s", &url))

return NULL;

sts = Recognise_Img(url);

return Py_BuildValue("s", sts.c_str() );

}

static PyMethodDef AllMyMethods[] = {

{"Recognise", Recognise, METH_VARARGS},//暴露给Python的函数

{NULL, NULL} /* Sentinel */

};

extern "C" PYUTIL_API void initpyUtil()

{

PyObject *m, *d;

m = Py_InitModule("pyUtil", AllMyMethods); //初始化本模块,并暴露函数

d = PyModule_GetDict(m);

}

在Python代码中调用这个动态链接库: (记得把dll的扩展名改为.pyd,另外dll的路径要能够被检索到)

import pyUtil

result = pyUtil.Recognise("input url of specific data")

print "the result is: "+ result

2、使用boost.python库来构建dll

用C++为Python写扩展时,如果您愿意使用Boost.Python库的话,开发过程会变得更开心J,要编写一个与上述pyUtil同样功能

的动态链接库,只需把文件内容替换为下面的代码。当然,编译需要boost_python.lib支持,运行需要boost_python.dll支持

#include

#include

using namespace boost::python;

#pragma comment(lib, "boost_python.lib")

std::string strtmp;

char const* Recognise(const char* url)

{

strtmp ="从dll中返回的数据... : ";

strtmp+=url;

return strtmp.c_str();

}

BOOST_PYTHON_MODULE(pyUtil)

{

def("Recognise", Recognise);

}

可以非常明显地看到,用了boost.python库之后,简单了很多。因为boost.python为你做了很多的事情。。恩。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值