c++中使用python

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。恩。

 

c++中嵌入python入門2

 

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爲你做了很多的事情。。恩。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章