2016-06-07 67 views
0

我們有一組使用Swig公開給Python的C++類。 我們經常爲這些方法增加新的參數。另一方面,我們有一套我們希望儘可能輕鬆維護的Python腳本。所以,當我們用C++更改暴露方法的參數集時,我們不希望更改所有使用此方法的python腳本。爲此,我們爲每個C++類創建了一個輔助接口類(C++類),它擁有一個指向原始類實例的指針並公開了一個簡化的接口。Swig:處理簡化接口的最佳方式

例如,假設我們有一個類A,與foo方法:

class A { 
    public : 
    void foo (int a, int b, double c, char * d, ....); 
}; 

並假設我們在Python快樂只有A,B和C的參數(通過默認值給其他人)。

我們創建一個APY類

class APy { 
public : 
    void foo(int a,int b, double c) { 
    A->foo(a,b,c,default,default,...); 
    } 
protected : 
    A * ref; 
}; 

的優點是有可能的新參數添加到A :: foo的,更改參數的命令,該方法的名稱,更一般地,對於更復雜在現有Python腳本中沒有任何改變的情況下對原始方法進行等同編碼。此外,如果一個腳本需要一個新的參數,可以通過APy :: foo中的默認參數添加它,而不必在原始的A :: foo方法中執行。

缺點是處理刪除操作很微妙,因爲有兩個對象。 APy被銷燬後我們應該刪除A嗎?這取決於。有時候A是一個較大對象的內部對象,不應該被銷燬。但是,只要Python腳本不再使用APy,它就應該被銷燬。

我想知道是否可以通過直接映射原始類和方法,而是通過請求swig映射和簡化參數列表本身來設計更直接但方便的體系結構。

在.i文件中,是否有可能要求Swig更改參數的順序,爲非暴露參數設置默認值(而不是.h默認值)?

舉例來說,如果我有一個函數

void foo(int a, double b, int c); 

,我想只保留A和C在腳本語言相反的順序,並設置b鍵10.0

所以,當我想撥打:

foo(3, 5) 

它實際上被映射到:

foo(5,10.0,3) 

無論如何,我希望聽到您的經驗,您認爲這是處理此類問題的最佳方法。

+0

swig在這裏是正確的工具嗎? Swig會自動顯示您所做的任何更改。這是你試圖阻止的事情。對於你想控制python API的python擴展,你可能想看看PyCXX。您必須爲自己定義類,但是您可以完全控制API,並且可以以適合您的方式提供向後兼容性。 –

+0

如果'A'和'APy'之間的關係是一對一的關係。即如果'APy'排他性擁有自己的'A'實例,那麼按照[RAII](https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization),您可以在APy的''A''中分配和釋放'A', c'tor'和'd'tor'分別。根據您的要求,APy將充當'A'的'Proxy'。 – sameerkn

+0

我不知道PyCXX。會看看。問題在於不可能爲其他腳本語言生成接口。 RAII設計會很好,但並不總是可能的。例如。想象一下Network :: getNode()方法的Network和Node類。返回的節點不應該被刪除,因爲節點是網絡對象的一部分(不是NodePy接口對象的一部分) –

回答

0

我認爲你可以用SWIG玩%ignore,%rename,%extend指令來好好解決你的問題。詳細信息請查看SWIG docs。要不是你上面的例子中,你可以使用下面的接口文件:

%module example 

%{ 
    #define SWIG_FILE_WITH_INIT 
%} 

%ignore A::foo(int a, double b, int c); 

%inline %{ 
    class A { 
    public : 
    double foo(int a, double b, int c) { 
     return a * b - c; 
    } 
    }; 
%} 

%extend A { 
    double foo(int c, int a) { 
    return $self->foo(a, 10.0, c); 
    } 
}; 

(注意,代替%inline %{ ... %}你當然也可以使用%{ #include "example.h" %}%include "example.h",如果你有一個頭文件中聲明你的功能。)

使用這種方法,無論何時更改C++代碼,都需要更新SWIG接口文件,但您應該能夠自定義暴露給Python的API。

還有一個應該知道的技巧,也就是說,您可以指示%ignore匹配更多,例如,所有方法,或A::foo的所有版本。但是在你使用%extend之前,你需要首先「取消」它們。因此,這裏是顯示這個(標準痛飲)招一個稍微複雜/高級的例子:

%module example 

%{ 
    #define SWIG_FILE_WITH_INIT 
%} 

%ignore A::foo; 

%inline %{ 
    class A { 
    public : 
    double foo(int a, double b, int c) { 
     return a * b - c; 
    } 
    double foo(int a, double b) { 
     return a * b; 
    } 
}; 
%} 

%rename("%s") A::foo; 

%extend A { 
    int foo(int c, int a) { 
    return $self->foo(a, 10.0, c); 
    } 
}; 

再次,看看夜風的文檔的具體細節。