本人是用vc2003 python2.5學(xué)習(xí)的,其它的也應(yīng)該差不了多少
0. 壞境設(shè)置
把Python的include/libs目錄分別加到vc的include/lib directories中去。另外,由于python沒有提供debug lib,體地說,就是沒有提供python25_d.lib了。你可以自己編譯python的源代碼來得到python25_d.lib的,偶還沒試過,呵呵。而且網(wǎng)上找了一下也沒下載到。所以,如果你想要在debug下運(yùn)行程序的話,你要把pyconfig.h(在python25/include/目錄下)的大概是在283行,把pragma comment(lib,'python25_d.lib')改成pragma comment(lib,'python25.lib'),讓python都使用非debug lib.
1. 開始編程了
#include
第一步就是包含python的頭文件
2. 看一個(gè)很簡單的例子
1)python文件test.py,很簡單的定義了一個(gè)函數(shù)
#Filename test.py
def Hello():
print 'Hello, world!'
這個(gè)應(yīng)該能看懂的吧?否則的話,回去再練練python吧,呵呵。《簡明Python教程》Swaroop, C. H. 著。沈潔元 譯。
2)cpp文件
#include
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之前,要調(diào)用Py_Initialize();這個(gè)函數(shù)進(jìn)行初始化。
幫助文檔中如是說:
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).
反正,一開始你一定要調(diào)用。
第三步,聲明一些Python的變量,PyObject類型的。其實(shí)聲明也可放在前面,這個(gè)倒是無所謂的。
第四步,import module,也就是你的腳本名字,不需要加后綴名,否則會(huì)出錯(cuò)的。
第五步,從你import進(jìn)來的module中得到你要的函數(shù)
pFunc = PyObject_GetAttrString(pModule, 'Hello');
上面的例子已經(jīng)夠清楚的了,最后一個(gè)是你要得到的函數(shù)的名字
第六步,調(diào)用PyEval_CallObject來執(zhí)行你的函數(shù),第二個(gè)參數(shù)為我們要調(diào)用的函數(shù)的函數(shù),本例子不含參數(shù),所以設(shè)置為NULL。
第七步,調(diào)用Py_Finalize,這個(gè)根Py_Initialize相對(duì)應(yīng)的。一個(gè)在最前面,一個(gè)在最后面。
第一次寫教程。這個(gè)例子非常簡單,本人也還在學(xué)習(xí)當(dāng)中阿,只能保證大家能夠把這個(gè)例子運(yùn)行起來。建議大家去看python的documentaion,里面有講怎么embedding python的。先寫到這里,其實(shí)目前也只學(xué)到這么多,呵呵。下次學(xué)了更多以后再寫。Over。恩。
1. 一個(gè)有一個(gè)參數(shù)的例子
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;
}
注意,參數(shù)要以tuple元組形式傳入。因?yàn)檫@個(gè)函數(shù)只要一個(gè)參數(shù),所以我們直接使用(s)構(gòu)造一個(gè)元組了。
2. 一個(gè)有兩個(gè)參數(shù)的例子
python文件中加入以下代碼,一個(gè)加函數(shù)
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了,開始使用新的函數(shù)
pArg = Py_BuildValue('(i,i)', 10, 15);//構(gòu)造一個(gè)元組
PyEval_CallObject(pFunc, pArg);
Py_Finalize();
return 0;
}
其它的就類似了。。?;旧希覀冎懒嗽趺丛赾 中使用python中的函數(shù)。接下來學(xué)習(xí)一下如何使用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. 首先講講元組的操作
由于參數(shù)是通過元組傳進(jìn)去的,所以我們不能老是通過Py_BuildValue這個(gè)函數(shù)來操作元組,那樣太不方便了。
Python提供了元組相關(guān)的操作,下面這個(gè)例子演示了如何操作。主要是下面幾個(gè)函數(shù):
//new一個(gè)元組,傳入size
pArgs = PyTuple_New(argc - 3);
//set元組的直,第一個(gè)為元組,第二個(gè)為index(從0開始),第三個(gè)為value
PyTuple_SetItem(pArgs,0,Py_BuildValue('i',2000) );
PyTuple_SetItem(pArgs,1,Py_BuildValue('i',8) );
來自python doc的一個(gè)例子
#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中去。定義了一個(gè)很簡單的類,有一個(gè)name成員變量,一個(gè)printName成員函數(shù)
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');//得到那個(gè)類
pArg = PyTuple_New(1);
PyTuple_SetItem(pArg, 0, Py_BuildValue('s', 'Jacky'));
pObject = PyEval_CallObject(pClass, pArg);//生成一個(gè)對(duì)象,或者叫作實(shí)例
pFunc = PyObject_GetAttrString(pObject, 'printName');//得到該實(shí)例的成員函數(shù)
PyEval_CallObject(pFunc, NULL);//執(zhí)行該實(shí)例的成員函數(shù)
Py_Finalize();
return 0;
}
沒有什么資料,就先寫到這里了。下面介紹一下怎么build python25的源代碼
3. 編譯python源代碼
為什么要編譯呢?因?yàn)闆]有python25_d.lib!呵呵。順便可以了解一下代碼結(jié)構(gòu)。
解壓縮后,有好多目錄,其中pcbuild和pcbuild8是我們要的。pcbuild對(duì)應(yīng)著vc7.1的,pcbuild8對(duì)應(yīng)著vc8.0的
因?yàn)樵谟胿c7.1,也就是2003了。所以我就說說怎么用2003來編譯吧。事實(shí)上是從一位牛人那里學(xué)來的
http://blog.donews.com/lemur/archive/2005/12/17/660973.aspx,那位大哥大概一年半前就在解剖python了,厲害
阿。看來我只能后來居上了,娃哈哈。我按照他說的試了一下,編譯成功!
不過遇到一點(diǎn)小問題,用vc2003打開那個(gè)solution的時(shí)候,發(fā)現(xiàn)作者沒有把source code control去掉,郁悶!害的我
們打開的時(shí)候一堆messagebox。不過不用管它就好了,一直確定。最后試了一下那個(gè)python25_d.lib,沒問題。不過記
得把python25_d.dll copy到一個(gè)能被找到的目錄,比如說c:/windows/system32/下面。python25.dll也在這個(gè)目錄下
面。over。恩。
壞境python25 vs2005 (2005真耗資源阿。。。)
有一段時(shí)間沒寫blog了。這幾天都在研究怎么封裝c ,讓python可以用c 的庫。在網(wǎng)上發(fā)現(xiàn)了boost.python這個(gè)好咚咚。不
過在使用過程中碰到一點(diǎn)問題。本文教大家如何把
char const* greet()
{
return 'hello, world';
}
封裝成python。實(shí)際上這是python教程里面的咚咚。
首先下載Boost,www.boost.org。boost.python在boost里面了。在visual studio 2005 command prompt中navigation到
boost/boost_1_34_0/下。記得一定要用visual studio 2005 command prompt這個(gè)vs2005帶的tools,不要用cmd.exe,否則會(huì)
碰到很多錯(cuò)誤的。然后就是把bjam.exe拷貝到一個(gè)能被找到的目錄下,或者直接也拷貝到boost/boost_1_34_0/下即可。然后,
設(shè)置python的根目錄和python的版本,也可直接把它們加到壞境目錄中,那樣就不用每次都設(shè)置一下。
set PYTHON_ROOT=c:/python25
set PYTHON_VERSION=2.5
接著就可以直接運(yùn)行了,bjam -sTOOLS=vc-8_0
整個(gè)編譯過程要很長時(shí)間。。。
成功之后,就會(huì)有好多個(gè)boost_python-vc80-****.dll,.lib的,把他們都拷貝到一個(gè)能被系統(tǒng)找到的目錄,不妨直接把他們都
扔到c:/windows/system32下。
接著,我們開始編譯hello。navigation到boost/boost_1_34_0/libs/python/example/tutorial下,bjam -sTOOLS=vc-8_0運(yùn)行
,在bin的目錄下即會(huì)生成hello.pyd。這下就基本成功了,如果沒成功的話,check一下上面boost_python的那些dll能否被系
統(tǒng)找到。另外,這里有python25的一個(gè)bug。。。我花了很長時(shí)間才在python的mail lists中找到了。寒。。。
錯(cuò)誤如下所示:
D:/Learn/Python/boost/boost_1_34_0/libs/python/example/tutorial>bjam
Jamroot:17: in modules.load
rule python-extension unknown in module Jamfile4_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.這個(gè)問題困擾了我好長時(shí)間。。sigh。。
。
編譯成功后會(huì)產(chǎn)生一個(gè)hello.pyd,在bin的目錄下面。
有好多辦法測試此hello.pyd是否可以用。
方法一,把它拷貝到python25/dlls下,打開IDLE,
>>> import hello
>>> hello.greet()
'hello, world'
>>>
方法二,直接在當(dāng)前目錄下寫一個(gè)python文件,然后直接調(diào)用hello.pyd即可??傊琱ello.pyd就是一個(gè)python文件了。。嗯
。操作hello.pyd根其他python文件是一樣的。
這樣就成功了。
如果碰到如下錯(cuò)誤,是因?yàn)橄到y(tǒng)找不到boost_python的dll。強(qiáng)烈建議把他們都扔到system32下!。
>>> import hello
Traceback (most recent call last):
File '
import hello
ImportError: DLL load failed: 找不到指定的模塊。
>>>
說明,hello.cpp在boost/boost_1_34_0/libs/python/example/tutorial目錄下。里面的內(nèi)容是:
// 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);
}
是對(duì)greet從c 向python的一個(gè)封裝聲明吧,裝換就交給boost了。
先寫到這里了。下次再寫。。嗯
這次講講,如何擴(kuò)展c 庫。通過boost.python把c 庫編譯成python能夠調(diào)用的dll。
通過上一次的教程后,大家都應(yīng)該會(huì)使用boost.python了。把c 程序編譯成pyd文件。由于c 有很多特性,所以,如果你的程
序用了很多的c 特性的話,那么你必須做很多工作了。像虛擬函數(shù),函數(shù)重載,繼承,默認(rèn)值等等。具體如何轉(zhuǎn)化,請(qǐng)參
boost.python的文檔了。
這幾天嘗試著把c 程序庫編譯成python可調(diào)用的dll,不知道為什么一直不可用。。很是郁悶。老是顯示如下的錯(cuò)誤:
Traceback (most recent call last):
File '
import pydll
ImportError: No module named pydll
意思是說找不到dll。我把dll都copy到python/dlls下了還是不行,而且我確定python的sys.path包含了python/dlls目錄了。
很是不解。網(wǎng)上也很難找到資料,google了很長時(shí)間找不到有用的資料,好像中文方面的資料很少的。今天嘗試了一下google
英文資料,終于有了新的發(fā)現(xiàn):
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/
有人碰到的問題跟我的是一樣的。后面那個(gè)Roman回答了一下,是文件擴(kuò)展名的問題!??!為什么不支持dll呢?不解?;厝ピ?/p>
了一下把后綴名改了就成功了。。。why???
下面來看一下我的那個(gè)簡單的例子:
這個(gè)例子來自于網(wǎng)上,
http://www.vckbase.com/document/viewdoc/?id=1540
C 擴(kuò)展和嵌入 Python
作者:胡金山
源碼下載地址:http://www.vckbase.com/code/downcode.asp?id=2777
這是一個(gè)非常簡單的dll工程。給python提供了一個(gè)函數(shù)static PyObject* Recognise(PyObject *self, PyObject *args)。
1、不使用boost.python庫來直接構(gòu)建dll
接下來,我們來用C 為Python編寫擴(kuò)展模塊(動(dòng)態(tài)鏈接庫),并在Python程序中調(diào)用C 開發(fā)的擴(kuò)展功能函數(shù)。生成一個(gè)取名為
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)
{
//返回結(jié)果
return '從dll中返回的數(shù)據(jù)... : ' 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的函數(shù)
{NULL, NULL} /* Sentinel */
};
extern 'C' PYUTIL_API void initpyUtil()
{
PyObject *m, *d;
m = Py_InitModule('pyUtil', AllMyMethods); //初始化本模塊,并暴露函數(shù)
d = PyModule_GetDict(m);
}
在Python代碼中調(diào)用這個(gè)動(dòng)態(tài)鏈接庫: (記得把dll的擴(kuò)展名改為.pyd,另外dll的路徑要能夠被檢索到)
import pyUtil
result = pyUtil.Recognise('input url of specific data')
print 'the result is: ' result
2、使用boost.python庫來構(gòu)建dll
用C 為Python寫擴(kuò)展時(shí),如果您愿意使用Boost.Python庫的話,開發(fā)過程會(huì)變得更開心J,要編寫一個(gè)與上述pyUtil同樣功能
的動(dòng)態(tài)鏈接庫,只需把文件內(nèi)容替換為下面的代碼。當(dāng)然,編譯需要boost_python.lib支持,運(yùn)行需要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中返回的數(shù)據(jù)... : ';
strtmp =url;
return strtmp.c_str();
}
BOOST_PYTHON_MODULE(pyUtil)
{
def('Recognise', Recognise);
}
可以非常明顯地看到,用了boost.python庫之后,簡單了很多。因?yàn)閎oost.python為你做了很多的事情。。恩。
聯(lián)系客服