swig 中的 %rename 和 %inline,错误检查

Jak*_* M. 2 python swig

我使用 SWIG 和 Numpy。我定义了一个 C 函数inplace()来快速处理数据数组,我想进行一些错误检查(如果两个数组具有相同的维度)。

我在文件中使用%rename和。据我了解,重命名应该映射函数名称,所以每次有人使用时,都会运行并检查错误。%inline.iinplacesafe_inplace

但它不起作用:(。据我所知,safe_inplace 没有被执行,python 直接运行inplace而不触及函数的安全版本。

# .i

%include "inplace.h"
%rename (inplace) safe_inplace;

%inline %{
    void safe_inplace(int* datain, int in_dx, int in_dy, int in_dz,
                      int* dataout, int out_dx, int out_dy)
    {
        if ((in_dx != out_dx) || (in_dy != out_dy)) { 
            PyErr_Format(PyExc_ValueError, /*... messgage*/) 
            return;
        } 

        inplace( /* .. pass the arguments to original function*/ );
    }
Run Code Online (Sandbox Code Playgroud)

头文件:

# .h 

void inplace(int* datain, int in_dx, int in_dy, int in_dz, int* dataout, int out_dx, int out_dy);
Run Code Online (Sandbox Code Playgroud)

Python:

#.py
inplace.inplace(a,b)
Run Code Online (Sandbox Code Playgroud)

我修改的原始示例可以在这里找到

Fle*_*exo 5

您最初的方法很接近,但您可能希望 SWIG 根本不包装该函数的原始版本。

我整理了一个稍微简单的例子来说明这是如何工作的。鉴于头文件:

void foo();
Run Code Online (Sandbox Code Playgroud)

我们想要包装它,以便在调用真正的版本之前调用稍微修改过的版本。

最简单的方法是从不实际显示 SWIG 头文件以进行包装,仅用于编译包装器,例如:

%module test

%{
#include "test.h"
#include <iostream>
%}

%rename (foo) foo_safe;
%inline %{
  void foo_safe() {
    std::cout << "Hello world" << std::endl;
    foo(); // Calls the foo() from test.h, as you'd hope
  }
%}
Run Code Online (Sandbox Code Playgroud)

如果您不想删除%include(例如,该头文件中还有您关心的其他内容),您可以执行以下操作:

%module test

%{
#include "test.h"
#include <iostream>
%}

%rename (unsafe_foo) foo;    
%include "test.h"

%rename (foo) foo_safe;    
%inline %{
  void foo_safe() {
    std::cout << "Hello world" << std::endl;
    foo();
  }
%}
Run Code Online (Sandbox Code Playgroud)

公开fooas的真实实现unsafe_foo

或者,%ignore如果 Python 用户没有理由能够调用unsafe_ignore,您可以使用:

%module test

%{
#include "test.h"
#include <iostream>
%}

%rename (foo) foo_safe;    
%inline %{
  void foo_safe() {
    std::cout << "Hello world" << std::endl;
    foo();
  }
%}

%ignore foo;    
%include "test.h"
Run Code Online (Sandbox Code Playgroud)

最后看起来您的目标实际上只是在调用真正的 C 函数之前运行一些代码。如果是这种情况,也有几种方法可以做到这一点,例如,您可以在使用以下命令进行真正的函数调用之前添加 python 代码pythonprepend

%feature("pythonprepend") foo() %{
   print "hello world"
   # check args and raise possibly 
%}
Run Code Online (Sandbox Code Playgroud)

或者最后您也可以使用该%exception功能,例如(未经测试):

%exception inplace {
   // Check args and possibly throw
   $action
}
Run Code Online (Sandbox Code Playgroud)

$action 将自动替换为真实调用。