2016-06-07 62 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); 
    } 
}; 

再次,看看夜风的文档的具体细节。