c++中嵌入python入門1
本人是用vc2003+python2.5學習的,其它的也應該差不了多少
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.
1. 開始編程了
#include <python.h>
第一步就是包含python的頭文件
2. 看一個很簡單的例子
1)python文件test.py,很簡單的定義了一個函數
#Filename test.py
def Hello():
print "Hello, world!"
這個應該能看懂的吧?否則的話,回去再練練python吧,呵呵。《簡明Python教程》Swaroop, C. H. 著。沈潔元 譯。
2)cpp文件
#include <python.h> //包含頭文件,在c++中嵌入python,這是必須的
int main()
{
Py_Initialize();
PyObject * pModule = NULL;
PyObject * pFunc = NULL;
pModule = PyImport_ImportModule("test");
pFunc = PyObject_GetAttrString(pModule, "Hello");
PyEval_CallObject(pFunc, NULL);
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))
c++中嵌入python入門3
這次主要講講怎么把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。恩。
c++中嵌入python入門4 之 Boost.Python
壞境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了。
先寫到這里了。下次再寫。。嗯
python與c++交互學習入門之5
這次講講,如何擴展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)。
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<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
2、使用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為你做了很多的事情。。恩。