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

发布于 2024-12-26 20:26:07 字数 1123 浏览 1 评论 0原文

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

我在 .i 文件中使用 %rename%inline 。据我了解,重命名应该映射函数名称,因此每次有人使用 inplace 时,都会运行 safe_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*/ );
    }

头文件:

# .h 

void inplace(int* datain, int in_dx, int in_dy, int in_dz, int* dataout, int out_dx, int out_dy);

Python:

#.py
inplace.inplace(a,b)

我修改的原始示例可以可以在此处找到

I use SWIG and Numpy. I define a C function called inplace() to process data array fast, and I want to make some error checking (if two arrays have the same dimentions).

I use %rename and %inline in the .i file. As I understand, rename should map the function names', so every time someone uses inplace, safe_inplace is run and the errors are checked.

But it does not work :( . As far I notice, safe_inplace is not executed, python runs directly inplace without touching the safe version of the function.

# .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*/ );
    }

header file:

# .h 

void inplace(int* datain, int in_dx, int in_dy, int in_dz, int* dataout, int out_dx, int out_dy);

Python:

#.py
inplace.inplace(a,b)

The original example that I modify can be found here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

执手闯天涯 2025-01-02 20:26:07

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

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

void foo();

我们希望将其包装起来,以便在调用真正的版本之前调用稍作修改的版本。

最简单的方法是从不实际显示 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
  }
%}

如果您不想删除 %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();
  }
%}

foo 的实际实现公开为 unsafe_foo

或者,如果 Python 用户没有理由能够调用 unsafe_ignore ,您可以使用 %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"

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

%feature("pythonprepend") foo() %{
   print "hello world"
   # check args and raise possibly 
%}

或者最后您可以使用 %exception< /code> 功能也是如此,类似(未经测试):

%exception inplace {
   // Check args and possibly throw
   $action
}

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

Your original approach was close, but you probably want to get SWIG not to wrap the original version of the function at all.

I've put together a slightly simpler example illustrating how this could work. Given the header file:

void foo();

We want to wrap it such that a slightly modified version is called before invoking the real one.

The simplest way to do this would be to never actually show SWIG the header file at all for wrapping, only for compiling the wrapper, e.g.:

%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
  }
%}

If you don't want to drop the %include (e.g. there's other things you care about in that header file too) you can do something like:

%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();
  }
%}

To expose the real implementation of foo as unsafe_foo.

Or you could use %ignore if there's no reason for Python users to be able to call unsafe_ignore ever:

%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"

Finally it looks like your goal is actually just to run some code prior to the call of the real C function. If that's the case there's a few ways you can do that too, for example you can add python code before the real function call is made with pythonprepend:

%feature("pythonprepend") foo() %{
   print "hello world"
   # check args and raise possibly 
%}

Or lastly you could use the %exception functionality too, something like (untested):

%exception inplace {
   // Check args and possibly throw
   $action
}

$action will be substituted with the real call automatically.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文