本人是用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爲你作了不少的事情。。恩。