本人是用vc2003+python2.5学习的,其它的也应该差不了多少html
0. 坏境设置
把Python的include/libs目录分别加到vc的include/lib directories中去。另外,因为python没有提供debug lib,体地说,就是没有提供python25_d.lib了。你能够本身编译python的源代码来获得python25_d.lib的,偶还没试过,呵呵。并且网上找了一下也没下载到。因此,若是你想要在debug下运行程序的话,你要把pyconfig.h(在python25/include/目录下)的大概是在283行,把pragma comment(lib,"python25_d.lib")改为pragma comment(lib,"python25.lib"),让python都使用非debug lib.python
1. 开始编程了
#include <python.h>
第一步就是包含python的头文件c++
2. 看一个很简单的例子
1)python文件test.py,很简单的定义了一个函数shell
#Filename test.py
def Hello():
print "Hello, world!"编程
这个应该能看懂的吧?不然的话,回去再练练python吧,呵呵。《简明Python教程》Swaroop, C. H. 著。沈洁元 译。bootstrap
2)cpp文件windows
#include <python.h> //包含头文件,在c++中嵌入python,这是必须的
int main()
{
Py_Initialize();函数
PyObject * pModule = NULL;
PyObject * pFunc = NULL;oop
pModule = PyImport_ImportModule("test");
pFunc = PyObject_GetAttrString(pModule, "Hello");
PyEval_CallObject(pFunc, NULL);post
Py_Finalize();
return 0;
}
第一步仍是包含头文件
第二步,使用python以前,要调用Py_Initialize();这个函数进行初始化。
帮助文档中如是说:
The basic initialization function is Py_Initialize(). This initializes the table of loaded modules, and creates the fundamental modules __builtin__, __main__, sys, and exceptions. It also initializes the module search path (sys.path).
反正,一开始你必定要调用。
第三步,声明一些Python的变量,PyObject类型的。其实声明也可放在前面,这个却是无所谓的。
第四步,import module,也就是你的脚本名字,不须要加后缀名,不然会出错的。
第五步,从你import进来的module中获得你要的函数
pFunc = PyObject_GetAttrString(pModule, "Hello");
上面的例子已经够清楚的了,最后一个是你要获得的函数的名字
第六步,调用PyEval_CallObject来执行你的函数,第二个参数为咱们要调用的函数的函数,本例子不含参数,因此设置为NULL。
第七步,调用Py_Finalize,这个根Py_Initialize相对应的。一个在最前面,一个在最后面。
第一次写教程。这个例子很是简单,本人也还在学习当中阿,只能保证你们可以把这个例子运行起来。建议你们去看python的documentaion,里面有讲怎么embedding python的。先写到这里,其实目前也只学到这么多,呵呵。下次学了更多之后再写。Over。恩。
1. 一个有一个参数的例子
python文件
#Filename test2.py
def Hello(s):
print "Hello, world!"
print s
cpp文件
#include <python.h>
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 <python.h>
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 <Python.h>
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 <python.h>
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来编译吧。事实上是从一位牛人那里学来的
http://blog.donews.com/lemur/archive/2005/12/17/660973.aspx,那位大哥大概一年半前就在解剖python了,厉害
阿。看来我只能后来居上了,娃哈哈。我按照他说的试了一下,编译成功!
不过遇到一点小问题,用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</D:/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 "<pyshell#0>", line 1, in <module>
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 <boost/python/module.hpp>
#include <boost/python/def.hpp>
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 "<pyshell#3>", line 1, in <module>
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???
下面来看一下个人那个简单的例子:
这个例子来自于网上,
http://www.vckbase.com/document/viewdoc/?id=1540
C++ 扩展和嵌入 Python
做者:胡金山
源码下载地址:http://www.vckbase.com/code/downcode.asp?id=2777
这是一个很是简单的dll工程。给python提供了一个函数static PyObject* Recognise(PyObject *self, PyObject *args)。
一、不使用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<windows.h>
#include<string>
#include<Python.h>
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
二、使用boost.python库来构建dll
用C++为Python写扩展时,若是您愿意使用Boost.Python库的话,开发过程会变得更开心J,要编写一个与上述pyUtil一样功能
的动态连接库,只需把文件内容替换为下面的代码。固然,编译须要boost_python.lib支持,运行须要boost_python.dll支持
。
#include<string>
#include <boost/python.hpp>
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为你作了不少的事情。。恩。