成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

利用 SWIG 對 C++ 庫進(jìn)行 Python 包裝

jas0n / 3503人閱讀

摘要:可以在接口文件中直接引用庫里的內(nèi)容,大大方便接口文件的編寫。使用庫里的這里先介紹方式通過創(chuàng)建出來的數(shù)組是數(shù)組的直接代理,非常底層和高效,但是,它也和數(shù)組一樣不安全,一樣沒有邊界檢查。對由于這種情況,可以使用庫里的。

如果你也像我們一樣,同時使用Python和C++,以獲得兩種語言的優(yōu)勢,一定也會希望尋找一種好的方式集成這兩種語言,相比而言,讓Python能夠方便使用C++的庫更加重要,我們選擇SWIG來實現(xiàn)這一需求,原因請見”途徑”一節(jié)對幾種實現(xiàn)途徑的比較。

這篇博文介紹使用SWIG將C++庫包裝成Python接口,建議將”常用功能說明”之后的內(nèi)容當(dāng)做參考使用,因為那些內(nèi)容牽涉到C++語言的各個特性,但不影響對SWIG整體使用的理解,可以在需要時參考。

另外,這篇博文中有很多例示代碼,解釋不多。是因為我覺得例示代碼本身是很好的解釋,清楚、準(zhǔn)確、簡練。如有問題,歡迎留言交流。

轉(zhuǎn)載者的話 by amc

本文章除了本小節(jié)是博主 amc 寫的之外,其他部分均為轉(zhuǎn)載,不同的是博主盡可能還原了原文的格式。

本文轉(zhuǎn)載自這里:“利用SWIG對C++庫進(jìn)行Python包裝”,然而這篇文章也是轉(zhuǎn)載的,但是卻不注明出處??!而原文到底是哪一篇、在哪里,也找不到了……

此外,那篇文章轉(zhuǎn)載了之后,但是只是普通的復(fù)制粘貼,格式什么的根本就不管,導(dǎo)致文章看起來實在是太難受了,所以我干脆自己轉(zhuǎn)載一份好了。如果本文章的原作者看到了,請務(wù)必聯(lián)系我,我會將最原創(chuàng)的鏈接完整附上。

最后,感謝原創(chuàng)者的貢獻(xiàn),同時譴責(zé)一下轉(zhuǎn)載不注明出處的博主們。

途徑

為C++庫提供Python接口有以下幾種常見途徑:

Python C API

Python解釋器提供的一組C API,利用這組API,可以用C/C++實現(xiàn)Python module,也可以將Python解釋器做為一個腳本引擎嵌入到C/C++程序中,為C/C++程序提供運(yùn)行Python腳本的能力。Python C API是其他途徑的基礎(chǔ),其他途徑最終都以某種方式以Python C API實現(xiàn)。然而,直接使用Python C API相當(dāng)繁瑣,容易出錯,因此很少直接使用。

ctypes

ctypes是Python標(biāo)準(zhǔn)庫提供的調(diào)用動態(tài)鏈接庫的模塊,使用這個模塊可以直接在Python里加載動態(tài)鏈接庫,調(diào)用其中的函數(shù)。使用ctypes 的優(yōu)勢是門檻低,不用編寫或修改C/C++代碼。然而我只簡單地使用過這種方式,沒有深入研究,不了解它對C/C++的支持是否完整。

Boost.Python

Boost.Python是Boost提供的一個C++的模板庫,用以支持Python和C++的無縫互操作。相對SWIG來說,這個庫的優(yōu)勢是功能通過C++ API完成,不用學(xué)習(xí)寫新的接口文件。對C++的支持更自然、完整。這個庫的問題是:1)有外部依賴;2)文檔不好,我看到有人說他看到三個不同的Boost.Python的tutorial,而這三個tutorial卻完全不一樣。我花了兩個小時嘗試Boost.Python,連tutorial的例子都沒跑通,就放棄了。

SWIG

SWIG是本文描述的重點,也是我們采用的途徑。SWIG完整支持ANSI C,支持除嵌套類外的所有C++特性。SWIG是一個接口編譯器,旨在為C/C++方便地提供腳本語言接口。SWIG不僅可以為C/C++程序生成 Python接口,目前可以生成CLISP,Java,Lua,PHP,Ruby,Tcl等19種語言的接口。SWIG被Subversion, wxPython, Xapian等項目使用。值得一提的是,Google也使用SWIG。

SWIG的工作方式

SWIG本質(zhì)上是個代碼生成器,為C/C++程序生成到其他語言的包裝代碼(wrapper code),這些包裝代碼里會利用各語言提供的C API,將C/C++程序中的內(nèi)容暴露給相應(yīng)語言。為了生成這些包裝代碼,SWIG需要一個接口描述文件,描述將什么樣的接口暴露給其他語言。

SWIG的 接口描述文件可以包含以下內(nèi)容:

ANSI C函數(shù)原型聲明

ANSI C變量聲明

SWIG指示器(directive)相關(guān)內(nèi)容

SWIG可以直接接受 .h 頭文件做為接口描述文件。在有了接口描述文件后,就可以利用 swig 命令生成包裝代碼了,然后將包裝代碼編譯鏈接成可被其他語言調(diào)用的庫。

SWIG對Python支持到何種程度?

利用SWIG,可以現(xiàn)實以下功能:

用Python調(diào)用C/C++庫

用Python繼承C++類,并在Python中使用該繼承類

C++使用Python擴(kuò)展(通過文檔描述應(yīng)該可以支持,未驗證)

版本說明

SWIG的最新版本為2.0.1。因為我們現(xiàn)在使用的SWIG版本為1.3.40,本篇博客里的說明僅針對1.3.40版

SWIG文檔說明

SWIG的文檔非常詳盡,我甚至覺得太過詳盡,不可能全看。我剛開始因為對SWIG文檔組織不熟悉,看完一部分SWIG Basices就開始嘗試,一路摸索到可以使用,后來才發(fā)現(xiàn)SWIG還有針對Python的專門文檔。相比之下我之前摸索到的方案相當(dāng)丑陋。

SWIG文檔大體分兩部分:

一部分為SWIG本身:SWIG基本使用,對C及C++的支持,SWIG庫及擴(kuò)展等

另一部分為SWIG對每一個目標(biāo)語言的文檔,如SWIG和Python的文檔。

我建議只看和具體語言相關(guān)的文檔,遇到問題時再去看SWIG本身的相關(guān)部分。

這篇博文應(yīng)該會描述到用SWIG對C++進(jìn)行Python包裝的各個方面,不過喜歡原汁原味且有充足時間又comfortable with English的同學(xué)可直接看SWIG的文檔。

SWIG包含的內(nèi)容

SWIG包含以下幾部分內(nèi)容:

一個代碼生成器(swig):代碼生成器根據(jù)接口說明文件,生成相應(yīng)的包裝代碼。

一個庫:SWIG將常用的內(nèi)容放到SWIG庫里了,比如對數(shù)組、指針的支持,字符串支持,STL支持等。可以在接口文件中直接引用庫里的內(nèi)容,大大方便接口文件的編寫。

一個簡單示例

本節(jié)給出一個簡單示例,提供對SWIG的直觀認(rèn)識,文章末尾處給出了一個更完整的例子。

example.h

#include 
using namespace std;
class Example{
    public:
    void say_hello();
};

example.cpp

#include "example.h"

void Example::say_hello(){
    cout<<"hello"<

example.i

%module example
%{
#include "example.h"
%}
%include "example.h"
setup.py
#!/usr/bin/env python

"""
setup.py file for SWIG C++/Python example
"""
from distutils.core import setup, Extension

example_module = Extension("_example",
    sources=["example.cpp", "example_wrap.cxx",],
)
setup (
    name = "example",
    version = "0.1",
    author = "www.99fang.com",
    description = """Simple swig C++/Python example""",
    ext_modules = [example_module],
    py_modules = ["example"],
)

運(yùn)行以下命令:

swig -c++ -python example.i
python setup.py build_ext --inplace

如果編譯無誤的話,就可以測試?yán)玻?/p>

>>> import example
>>> example.Example().say_hello()
hello

以上我用distutils構(gòu)建了example module,也可以通過編譯器直接構(gòu)建, 比如:

gcc -fPIC -I/usr/include/python2.5/ -lstdc++ -shared -o _example.so example_wrap.cxx example.cpp

注意,-fPIC和-lstdc++都是必要的。_example.so前的’_"也是必要的。

SWIG生成代碼說明

swig -c++ -python example.i 命令生成了兩個文件:example_wrap.cxx, example.py。example_wrap.cxx里會對Example類提供類使以下的扁平接口:

Example* new_Example();
void say_hello(Example* example);
viod delete_Example(Example *example);

這個接口被編譯到_example.so里,_example可以做為一個 Python module 直接加載到 Python 解釋器中。 example.py 利用 _example 里提供的接口,將扁平的接口還原為 Python 的 Example 類,這個類做為 C++ Example 類的代理類型,這樣使用方式就更加自然了。

SWIG接口文件的結(jié)構(gòu)

SWIG 接口文件指導(dǎo) SWIG 生成包裝代碼,其中包含 %module 聲明,接口聲明 (%include “example.h”),以及 %{ … %} 中的內(nèi)容。%{ … %} 中的內(nèi)容會原封不動地拷貝到生成的包裝代碼中,上節(jié)例子中的 #include “example.h” 是必要的,因為接口聲明中僅是聲明接口中要暴露哪些內(nèi)容(Example類),但如果沒有 #include “example.h” 的話,生成的包裝代碼是無法通過編譯的。

常用功能說明 處理輸入輸出參數(shù)

C++包裝的一個常見問題是有的C++函數(shù)以指針做為函數(shù)參數(shù), 如:

void add(int x, int y, int *result) {
    *result = x + y;
}

int sub(int *x, int *y) {
    return *x-*y;
}

處理這種情況的最方便方式是使用SWIG庫里的typemaps.i (關(guān)于SWIG庫和Typemap見之后內(nèi)容):

%module example
%include "typemaps.i"

void add(int, int, int *OUTPUT);
int sub(int *INPUT, int *INPUT);

>>> a = add(3,4)
>>> print a
7
>>> b = sub(7,4)
>>> print b
3

另一種寫法:

%module example
%include "typemaps.i"

%apply int *OUTPUT { int *result };
%apply int *INPUT { int *x, int *y};

void add(int x, int y, int *result);
int sub(int *x, int *y);

對于既是輸入又是輸出參數(shù)的處理:

void negate(int *x) {
*x = -(*x);
}
-----------------------------
%include "typemaps.i"
...
void negate(int *INOUT);

-----------------------------
>>> a = negate(3)
>>> print a
-3

對于多個返回參數(shù)的處理:

/* send message, return number of bytes sent, along with success code */
int send_message(char *text, int len, int *success);
-----------------------------

%module example
%include "typemaps.i"
%apply int *OUTPUT { int *success };
...
int send_message(char *text, int *success);
-----------------------------

bytes, success = send_message("Hello World")
if not success:
print "Whoa!"
else:
print "Sent", bytes

當(dāng)輸出都通過參數(shù)給出情況的處理:

void get_dimensions(Matrix *m, int *rows, int *columns);

%module example
%include "typemaps.i"
%apply int *OUTPUT { int *rows, int *columns };
...
void get_dimensions(Matrix *m, int *rows, *columns);

>>> r,c = get_dimensions(m)

注意,typemaps.i只支持了基本數(shù)據(jù)類型,所以不能寫void foo(Bar *OUTPUT);,因為typemaps.i里沒有對Bar定義OUTPUT規(guī)則。

C數(shù)組實現(xiàn)

有的C函數(shù)要求傳入一個數(shù)組作為參數(shù),調(diào)用這種函數(shù)時不能直接傳入一個Python list或tuple, 有三種方式能解決這個問題:

使用類型映射(Typemap), 將數(shù)組代碼生成為Python list或tuple相應(yīng)代碼使用輔助函數(shù),用輔助函數(shù)生成和操作數(shù)組對象,再結(jié)合在接口文件中插入一些Python代碼,也可使Python直接傳入list或tuple。這種方式在之后說明。使用SWIG庫里的carrays.i
這里先介紹carrays.i方式:

int sumitems(int *first, int nitems) {
    int i, sum = 0;
    for (i = 0; i < nitems; i++) {
        sum += first[i];
    }
    return sum;
}

%include "carrays.i"
%array_class(int, intArray);

>>> a = intArray(10000000) # Array of 10-million integers
>>> for i in xrange(10000): # Set some values
... a[i] = i
>>> sumitems(a,10000)
49995000

通過 %array_class 創(chuàng)建出來的數(shù)組是C數(shù)組的直接代理,非常底層和高效,但是,它也和C數(shù)組一樣不安全,一樣沒有邊界檢查。

C/C++輔助函數(shù)

可以通過輔助函數(shù)來完一些SWIG本身不支持的功能。事實上,輔助函數(shù)可謂SWIG包裝的瑞士軍刀,一旦了解它使用,你可以使SWIG支持幾乎所有你需要的功能,不過提醒一下,有很多C++特性是SWIG本身支持或者通過庫支持的,不需要通過輔助函數(shù)實現(xiàn)。

同樣的,直接上例示代碼:

void set_transform(Image *im, double m[4][4]);

>>> a = [
... [1,0,0,0],
... [0,1,0,0],
... [0,0,1,0],
... [0,0,0,1]]
>>> set_transform(im,a)
Traceback (most recent call last):
File "", line 1, in ?
TypeError: Type error. Expected _p_a_4__double

可以看到,set_transform是不能接受Python二維List的,可以用輔助函數(shù)幫助實現(xiàn):

%inline %{
    /* Note: double[4][4] is equivalent to a pointer to an array double (*)[4] */
    double (*new_mat44())[4] {
    return (double (*)[4]) malloc(16*sizeof(double));
}
void free_mat44(double (*x)[4]) {
    free(x);
}
void mat44_set(double x[4][4], int i, int j, double v) {
    x[i][j] = v;
}
double mat44_get(double x[4][4], int i, int j) {
    return x[i][j];
}
%}

>>> a = new_mat44()
>>> mat44_set(a,0,0,1.0)
>>> mat44_set(a,1,1,1.0)
>>> mat44_set(a,2,2,1.0)
...
>>> set_transform(im,a)
>>>

當(dāng)然,這樣使用起來還不夠優(yōu)雅,但可以工作了,接下來介紹通過插入額外的Python代碼來讓使用優(yōu)雅起來。

插入額外的Python代碼

為了讓set_transform函數(shù)接受Python二維list或tuple,我們可以對它的Python代碼稍加改造:

void set_transform(Image *im, double x[4][4]);

...
/* Rewrite the high level interface to set_transform */
%pythoncode %{
    def set_transform(im,x):
    a = new_mat44()
    for i in range(4):
    for j in range(4):
    mat44_set(a,i,j,x[i][j])
    _example.set_transform(im,a)
    free_mat44(a)
%}

>>> a = [
... [1,0,0,0],
... [0,1,0,0],
... [0,0,1,0],
... [0,0,0,1]]
>>> set_transform(im,a)

SWIG還提供了%feature(“shadow”), %feature(“pythonprepend”), %feature(“pythonappend”)來支持重寫某函數(shù)的代理函數(shù),或在某函數(shù)前后插入額外代碼,在%feature(“shadow”)中 可用$action來指代對C++相應(yīng)函數(shù)的調(diào)用:

%module example

// Rewrite bar() python code

%feature("shadow") Foo::bar(int) %{
def bar(*args):
#do something before
$action
#do something after
%}

class Foo {
    public:
       int bar(int x);
}

或者:

%module example

// Add python code to bar() 

%feature("pythonprepend") Foo::bar(int) %{
#do something before C++ call
%}

%feature("pythonappend") Foo::bar(int) %{
#do something after C++ call
%}

class Foo {
public:
int bar(int x);
}
用%extend指示器擴(kuò)展C++類

你可以通過%extend指示器擴(kuò)展C++類,甚至可用通過這種方式重載Python運(yùn)算符:

%module example
%{
#include "someheader.h"
%}

struct Vector {
   double x,y,z;
};

%extend Vector {
char *__str__() {
    static char tmp[1024];
    sprintf(tmp,"Vector(%g,%g,%g)", $self->x,$self->y,$self->z);
    return tmp;
}
Vector(double x, double y, double z) {
    Vector *v = (Vector *) malloc(sizeof(Vector));
    v->x = x;
    v->y = y;
    v->z = z;
    return v;
}

Vector __add__(Vector *other) {
    Vector v;
    v.x = $self->x + other->x;
    v.y = $self->y + other->y;
    v.z = $self->z + other->z;
    return v;
}

};

>>> v = example.Vector(2,3,4)
>>> print v
Vector(2,3,4)
>>> v = example.Vector(2,3,4)
>>> w = example.Vector(10,11,12)
>>> print v+w
Vector(12,14,16)

注意,在%extend里this用$self代替。

字符串處理

SWIG將char 映射為Python的字符串,但是Python字符串是不可修改的(immutable),如果某函數(shù)有修改char ,很可能導(dǎo)致Python解釋器崩潰。對由于這種情況,可以使用SWIG庫里的cstring.i。

模塊

SWIG通過%module指示器指定Python模塊的名字

函數(shù)及回調(diào)函數(shù)

全局函數(shù)被包裝為%module指示模塊下的函數(shù),如:

%module example
int add(int a, int b);

>>>import example
>>>print example.add(3, 4)
7
全局變量

SWIG創(chuàng)建一個特殊的變量’cvar’來存取全局變量,如:

%module example
%inline %{
double density = 2.5;
%}

>>>import example
>>>print example.cvar.density
2.5

inline是另一個常見的SWIG指示器,用來在接口文件中插入C/C++代碼,并將代碼中聲明的內(nèi)容輸出到接口中。

常量和枚舉變量

用#define, enum或者%constant指定常量:

#define PI 3.14159
#define VERSION "1.0"

enum Beverage { ALE, LAGER, STOUT, PILSNER };

%constant int FOO = 42;
%constant const char *path = "/usr/local";
指針,引用,值和數(shù)組

SWIG完整地支持指針:

%module example

FILE *fopen(const char *filename, const char *mode);
int fputs(const char *, FILE *);
int fclose(FILE *);

>>> import example
>>> f = example.fopen("junk","w")
>>> example.fputs("Hello World
", f)
>>> example.fclose(f)
>>> print f

>>> print str(f)
_c0671108_p_FILE

指針的裸值可以通過將指針對象轉(zhuǎn)換成int獲得,不過,無法通過一個int值構(gòu)造出一個指針對象。

>>> print int(f)
135833352

’0′或NULL被表示為None.

對指針的類型轉(zhuǎn)換或運(yùn)算必須通過輔助函數(shù)完成,特殊要注意的是,對C++指針的類型轉(zhuǎn)換,應(yīng)該用C++方式的轉(zhuǎn)換,而不是用C方式的轉(zhuǎn)換,因為在轉(zhuǎn)換無法完成是,C++方式的轉(zhuǎn)換會返回NULL,而C方式的轉(zhuǎn)換會返回一個無效的指針:

%inline %{
/* C-style cast */
Bar *FooToBar(Foo *f) {
    return (Bar *) f;
}

/* C++-style cast */
Foo *BarToFoo(Bar *b) {
   return dynamic_cast(b);
}

Foo *IncrFoo(Foo *f, int i) {
   return f+i;
}

在C++中,函數(shù)參數(shù)可能是指針,引用,常量引用,值,數(shù)據(jù)等,SWIG將這些類型統(tǒng)一為指針類型處理(通過相應(yīng)的包裝代碼):

void spam1(Foo *x); // Pass by pointer
void spam2(Foo &x); // Pass by reference
void spam3(const Foo &x);// Pass by const reference
void spam4(Foo x); // Pass by value
void spam5(Foo x[]); // Array of objects

>>> f = Foo() # Create a Foo
>>> spam1(f) # Ok. Pointer
>>> spam2(f) # Ok. Reference
>>> spam3(f) # Ok. Const reference
>>> spam4(f) # Ok. Value.
>>> spam5(f) # Ok. Array (1 element)

返回值是也同樣的:

Foo *spam6();
Foo &spam7();
Foo spam8();
const Foo &spam9();

這些函數(shù)都會統(tǒng)一為返回一個Foo指針。

結(jié)構(gòu)和類,以及繼承
結(jié)構(gòu)和類是以Python類來包裝的:

struct Vector {
   double x,y,z;
};

>>> v = example.Vector()
>>> v.x = 3.5
>>> v.y = 7.2
>>> print v.x, v.y, v.z
7.8 -4.5 0.0
>>>

如果類或結(jié)構(gòu)中包含數(shù)組,該數(shù)組是通過指針來操縱的:

struct Bar {
int x[16];
};

>>> b = example.Bar()
>>> print b.x
_801861a4_p_int
>>>

對于數(shù)組賦值,SWIG會做數(shù)據(jù)的值拷貝:

>>> c = example.Bar()
>>> c.x = b.x # Copy contents of b.x to c.x

但是,如果一個類或結(jié)構(gòu)中包含另一個類或結(jié)構(gòu)成員,賦值操作完全和指針操作相同。
對于靜態(tài)類成員函數(shù),在Python中有三種訪問方式:

class Spam {
    public:
        static int bar;
        static void foo();
};

>>> example.Spam_foo() # Spam::foo()
>>> s = example.Spam()
>>> s.foo() # Spam::foo() via an instance
>>> example.Spam.foo() # Spam::foo(). Python-2.2 only

其中第三種方式Python2.2及以上版本才支持,因為之前版本的Python不支持靜態(tài)類成員函數(shù)。

靜態(tài)類成員變量以全局變量方式獲?。?/p>

>>> print example.cvar.Spam_bar

SWIG支持C++繼承,可以用Python工具函數(shù)驗證這一點:

class Foo {
    ...
};

class Bar : public Foo {
    ...
};

>>> b = Bar()
>>> instance(b,Foo)
1
>>> issubclass(Bar,Foo)
1
>>> issubclass(Foo,Bar)
0

同時,如果有形如void spam(Foo *f);的函數(shù),可以傳b = Bar()進(jìn)去。

SWIG支持多繼承。

重載

SWIG支持C++重載:

void foo(int);
void foo(char *c);

>>> foo(3) # foo(int)
>>> foo("Hello") # foo(char *c)
但是,SWIG不能支持所有形式的C++重載,如:

void spam(int);
void spam(short);

void foo(Bar *b);
void foo(Bar &b);

這種形式的聲明會讓SWIG產(chǎn)生警告,可以通過重名命或忽略其中一個來避免這個警告:

%rename(spam_short) spam(short);

%ignore spam(short);
運(yùn)算符重載

SWIG能夠自動處理運(yùn)算符重載:

class Complex {
    private:
        double rpart, ipart;
    public:
        Complex(double r = 0, double i = 0) : rpart(r), ipart(i) { }
        Complex(const Complex &c) : rpart(c.rpart), ipart(c.ipart) { }
        Complex &operator=(const Complex &c);
        
        Complex operator+=(const Complex &c) const;
        Complex operator+(const Complex &c) const;
        Complex operator-(const Complex &c) const;
        Complex operator*(const Complex &c) const;
        Complex operator-() const;
        
        double re() const { return rpart; }
        double im() const { return ipart; }
};

>>> c = Complex(3,4)
>>> d = Complex(7,8)
>>> e = c + d
>>> e.re()
10.0
>>> e.im()
12.0
>>> c += d
>>> c.re()
10.0
>>> c.im()
12.0

如果重載的運(yùn)算符不是類的一部分,SWIG無法直接支持,如:

class Complex {
    ...
    friend Complex operator+(double, const Complex &c);
    ...
};

這種情況下SWIG是報一個警告,不過還是可以通過一個特殊的函數(shù),來包裝這個運(yùn)算符:

%rename(Complex_add_dc) operator+(double, const Complex &);

不過,有的運(yùn)算符無法清晰地映射到Python表示,如賦值運(yùn)算符,像這樣的重載會被忽略。

名字空間

名字空間不會映射成Python的模塊名,如果不同名字空間有同名實體要暴露到接口中,可以通過重命名指示器解決:

%rename(Bar_spam) Bar::spam;

namespace Foo {
    int spam();
}

namespace Bar {
    int spam();
}
模板

SWIG對C/C++的包裝是二進(jìn)制級別的,但C++模板根本不是二進(jìn)制級別的概念,所以對模板的包裝需要將模板實例化,SWIG提供%template指示器支持這項功能:

%module example
%{
#include "pair.h"
%}

template
struct pair {
    typedef T1 first_type;
    typedef T2 second_type;
    T1 first;
    T2 second;
    pair();
    pair(const T1&, const T2&);
    ~pair();
};

%template(pairii) pair;

>>> import example
>>> p = example.pairii(3,4)
>>> p.first
3
>>> p.second
4

如果你要同時映射一個模板,以及以這個模板為參數(shù)的另一個模板,還要做一點特殊的工作, 比如,同時映射pair< string, string >和 vector< pair >,需要像下面這樣做:

%module testpair
%include "std_string.i"
%include "std_vector.i"
%include "std_pair.i"
%{
#include 
#include 
#include 
using namespace std;
%}

%template(StringPair) std::pair;
SWIG_STD_VECTOR_SPECIALIZE_MINIMUM(StringPair, std::pair< std::string, std::string >);
%template(StringPairVector) std::vector< std::pair >;

遺憾的是,我并沒有在文檔中發(fā)現(xiàn)對這種做法的說明,以上做法是在swig用戶組中問到的。

智能指針

有的函數(shù)的返回值是智能指針,為了調(diào)用這樣的函數(shù),只需要對智能指針類型做相應(yīng)聲明:

%module example
...
%template(SmartPtrFoo) SmartPtr;
...

>>> p = example.CreateFoo() # CreatFool()返回一個SmartPtr
>>> p.x = 3 # Foo::x
>>> p.bar() # Foo::bar

可以通過p.__deref__()得到相應(yīng)的Foo*

引用記數(shù)對象支持

對于使用引用記數(shù)慣例的C++對象,SWIG提供了%ref和%unref指示器支持,使用Python里使用時不用手工調(diào)用ref和unref函數(shù)。因為我們目前沒有使用引用記數(shù)技術(shù),具體細(xì)節(jié)這里不詳述了。

內(nèi)存管理

SWIG是通過在Python里創(chuàng)建C++相應(yīng)類型的代理類型來包裝C++的,每個Python代理對象里有一個.thisown的標(biāo)志,這個標(biāo)志 決定此代理對象是否負(fù)責(zé)相應(yīng)C++對象的生命周期:如果.thisown這個標(biāo)志為1,Python解釋器在回收Python代理對象時也會銷毀相應(yīng)的 C++對象,如果沒有這個標(biāo)志或這個標(biāo)志的值是0,則Python代理對象回收時不影響相應(yīng)的C++對象。

當(dāng)創(chuàng)建對象,或通過值返回方式獲得對象時,代理對象自動獲得.thisown標(biāo)志。當(dāng)通過指針方式獲得對象時,代理對象.thisown的值為0:

class Foo {
    public:
        Foo();
        Foo bar();
        Foo *spam();
};

>>> f = Foo()
>>> f.thisown
1
>>> g = f.bar()
>>> g.thisown
1
>>> f = Foo()
>>> s = f.spam()
>>> print s.thisown
0

當(dāng)這種行為不是期望的行為的時候,可以人工設(shè)置這個標(biāo)志的值:

>>> v.thisown = 0
跨語言多態(tài)

當(dāng)你希望用Python擴(kuò)展(繼承)C++的類型的時候,你就需要跨語言多態(tài)支持了。SWIG提供了一個調(diào)度者(director)特性支持此功能,但此特性默認(rèn)是關(guān)閉的,通過以下方式打開此特性:

首先,在module指示器里打開

%module(directors="1") modulename

其次,通過%feature指示器告訴SWIG哪些類和函數(shù)需要跨語言多態(tài)支持:

// generate directors for all classes that have virtual methods
%feature("director"); 

// generate directors for all virtual methods in class Foo
%feature("director") Foo; 

// generate a director for just Foo::bar()
%feature("director") Foo::bar;

可以使用%feature(“nodirector”)指示器關(guān)閉某個類型或函數(shù)的的跨語言多態(tài)支持:

%feature("director") Foo;
%feature("nodirector") Foo::bar;
類型映射(Typemaps)

類型映射是SWIG最核心的一部分,類型映射就是告訴SWIG對某個C類型,生成什么樣的代碼。不過,SWIG的文檔里說類型映射是SWIG的高級自定義部分,不是使用SWIG需要理解的,除非你要提升自己的NB等級

以下的類型映射可用于將整數(shù)從Python轉(zhuǎn)換為C:

%module example

%typemap(in) int {
    $1 = (int) PyLong_AsLong($input);
    printf("Received an integer : %d
",$1);
}
%inline %{
    int add(int a, int b){
    return a+b;
}
%}

>>> import example
>>> example.add(3,4)
Received an integer : 3
Received an integer : 4
7
SWIG庫

SWIG提供了一組庫文件,用以支持常用的包裝,如數(shù)組,標(biāo)準(zhǔn)庫等??梢栽诮涌谖募幸脒@些庫文件。比如,在%include “std_string.i”后,就可以直接給需要string參數(shù)數(shù)的函數(shù)傳Python字符串了。對”std_vector.i”舉例如下:

%module example
%include "std_vector.i"

namespace std {
%template(vectori) vector;
};

>>> from example import *
>>> v = vectori()
>>> v.push_back(1)
>>> print v.size()
1
參考資料

SWIG和Python: http://www.swig.org/Doc1.3/SWIGDocumentation.html#Python

SWIG基礎(chǔ): http://www.swig.org/Doc1.3/SWIGDocumentation.html#SWIG

SWIG和C++: http://www.swig.org/Doc1.3/SWIGDocumentation.html#SWIGPlus

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/41402.html

相關(guān)文章

  • Python的C/C++擴(kuò)展——用SWIG封裝C++Python模塊

    摘要:所以,最大的好處就是將腳本語言的開發(fā)效率和的運(yùn)行效率有機(jī)的結(jié)合起來。前面的文章提到一個實現(xiàn)的雙數(shù)組的實現(xiàn),它在中文分詞新詞發(fā)現(xiàn)等算法中的應(yīng)用。本文以的封裝實現(xiàn)來說明的使用。編譯生成動態(tài)庫編譯生成的使用的,可以參考的編寫。 如果覺得文章對你有幫助,你也可以訪問老猿的個人博客https://www.yuanrenxue.com/ Python調(diào)用C/C++代碼的利器除了boost_pyt...

    鄒強(qiáng) 評論0 收藏0
  • 深度學(xué)習(xí):你該知道八大開源框架

    摘要:作為當(dāng)下最熱門的話題,等巨頭都圍繞深度學(xué)習(xí)重點投資了一系列新興項目,他們也一直在支持一些開源深度學(xué)習(xí)框架。八來自一個日本的深度學(xué)習(xí)創(chuàng)業(yè)公司,今年月發(fā)布的一個框架。 深度學(xué)習(xí)(Deep Learning)是機(jī)器學(xué)習(xí)中一種基于對數(shù)據(jù)進(jìn)行表征學(xué)習(xí)的方法,深度學(xué)習(xí)的好處是用 非 監(jiān)督式或半監(jiān)督式 的特征學(xué)習(xí)、分層特征提取高效算法來替代手工獲取特征(feature)。作為當(dāng)下最熱門的話題,Google...

    Rindia 評論0 收藏0
  • Tensorflow代碼解析(二)

    摘要:為了進(jìn)一步了解的邏輯,圖對和進(jìn)行了展開分析。另外,在命名空間中還隱式聲明了控制依賴操作,這在章節(jié)控制流中相關(guān)說明。簡述是高效易用的開源庫,有效支持線性代數(shù),矩陣和矢量運(yùn)算,數(shù)值分析及其相關(guān)的算法。返回其中一塊給用戶,并將該內(nèi)存塊標(biāo)識為占用。 3. TF 代碼分析初步3.1 TF總體概述為了對TF有整體描述,本章節(jié)將選取TF白皮書[1]中的示例展開說明,如圖 3 1所示是一個簡單線性模型的TF...

    zhigoo 評論0 收藏0
  • Python調(diào)用C/C++方式

    摘要:調(diào)用方式方式一基礎(chǔ)篇這種方法叫做的擴(kuò)展使用這樣調(diào)用引用的頭文件包裹函數(shù),用來包裹需要轉(zhuǎn)化為的函數(shù),在方法前面加下劃線。定義名稱通常和文件名保持一致。執(zhí)行命令在下,使用編譯器生成對應(yīng)的文件。 Python調(diào)用C++方式 方式一(基礎(chǔ)篇) 這種方法叫做python的擴(kuò)展 int great_function(int a) { return a + 1; } 使用python這樣調(diào)用...

    PiscesYE 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<