我们有一组C ++类,我们使用Swig向Python公开。 我们经常在方法中添加新的参数。 另一方面,我们有一组Python脚本,我们希望尽可能轻松地维护它们。因此,当我们在C ++中更改公开方法的参数集时,我们不希望必须更改所有使用此方法的python脚本。为此,我们为每个C ++类创建了一个辅助接口类(也是C ++类),它拥有指向原始类实例的指针并公开了一个简化的接口。
例如,假设我们有一个带有方法foo的类A: 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 :(得分:0)
我认为您可以通过使用%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
之前,你需要首先“取消发现”它们。所以这里有一个稍微多一点的参与/高级示例,显示了这个(标准的SWIG)技巧:
%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);
}
};
再次,详细了解SWIG文档。