python的in和out怎么用_关于python:在typemap中使用SWIG可以,但是argout不能

我有这个文件foobar.h

class Foobar {

public: void method(int arg[2]) {};

};

在将SWIG接口编译为Python之后,如果我尝试从Python运行此方法,则会显示

TypeError: in method 'Foobar_method', argument 2 of type 'int [2]'

当然。 所以我写了这个SWIG类型图:

%typemap(in) int [2] {}

当我编译它时,Python运行此方法时不会抱怨。 所以我想,我了解如何编写类型图。

但是,如果我将类型映射更改为argout:

%typemap(argout) int [2] {}

现在,Python返回上一个错误。

我只是直接从SWIG手册中执行此操作,它应该可以正常工作而不会出现该错误,就像in typemap。

我究竟做错了什么???

怎么了?

简而言之,这些类型图不是一个或非命题。

您缺少的关键信息是多个类型映射共同包装单个函数的方式。

调用发生后,argout将插入到生成的包装器中。您有机会以明智的方式将(现在已修改的)输入复制回Python。

但是,这并没有解决在调用之前如何创建和传递参数的问题。

通过检查此接口生成的代码,您可以很清楚地看到这一点:

%module test

%{

#include"test.h"

%}

%typemap(in) int[2] {

//"In" typemap goes here

}

%typemap(argout) int[2] {

//"argout" goes here

}

%include"test.h"

当您的示例是test.h时,会产生以下结果:

// ...

arg1 = reinterpret_cast< Foobar * >(argp1);

{

//"In" typemap goes here

}

(arg1)->method(arg2);

resultobj = SWIG_Py_Void();

{

//"argout" goes here

}

return resultobj;

// ...

在这些类型映射中," in"类型映射的目标是在调用之前使arg2成为一个有意义的值,而" argout"类型映射应该对调用之后的值做出明智的选择(如果需要,可以通过更改返回值) 。

类型图中应该是什么?

通常,对于类似这样的函数,您可能希望输入类型映射由一些Python输入填充一个临时数组。

为此,我们需要首先更改输入类型图,要求SWIG为我们创建一个临时数组:

重要的是,让SWIG为我们做到这一点,使用在类型之后添加括号的表示法,而不是在类型映射的主体内添加括号,以使作用域对变量正确。 (如果我们不这样做的话,临时对象将仍然无法从" argout"类型映射中访问,并且在调用自身之前将其清除)。

%typemap(in) int[2] (int temp[2]) {

// If we defined the temporary here then it would be out of scope too early.

//"In" typemap goes here

}

SWIG生成的代码现在为我们包括了该临时数组,因此我们想使用Python C API迭代输入。可能看起来像:

%typemap(in) int[2] (int temp[2]) {

//"In" typemap goes here:

for (Py_ssize_t i = 0; i < PyList_Size($input); ++i) {

assert(i < sizeof temp/sizeof *temp); // Do something smarter

temp[i] = PyInt_AsLong(PyList_GetItem($input, i)); // Handle errors

}

$1 = temp; // Use the temporary as our input

}

(如果愿意,我们可以选择使用Python迭代器协议)。

如果现在编译并运行接口,则我们有足够的能力来传递输入,但是什么也没回来。在我们编写" argout"类型映射之前,在生成的代码中还需要注意一件事。生成的代码中的临时数组实际上看起来像int temp2[2]。没错,SWIG默认情况下已重命名了要从参数位置派生的变量,以允许将同一类型映射多次应用于单个函数调用,如果需要,每个参数一次。

在" argout"类型图中,我将返回另一个带有新值的Python列表。从长远来看,这并不是唯一明智的选择-如果您愿意,还有其他选择。

%typemap(argout) int[2] {

//"argout" goes here:

PyObject *list = PyList_New(2);

for (size_t i = 0; i < 2; ++i) {

PyList_SetItem(list, i, PyInt_FromLong(temp$argnum[i]));

}

$result = list;

}

需要注意的两点是,首先我们需要显式编写temp$argnum,以匹配SWIG对临时数组所做的转换,其次,我们将$result用作输出。

纯输出参数

通常,我们有一个仅用于输出而不是输入的参数。对于这些,强制Python用户提供将被忽略的列表是没有意义的。

我们可以通过使用numinputs=0修改" in"类型映射来完成此操作,以指示不需要Python输入。您还需要在这里适当地初始化临时文件。现在,类型图变得简单:

%typemap(in,numinputs=0) int[2] (int temp[2]) {

//"In" typemap goes here:

memset(temp, 0, sizeof temp);

$1 = temp;

}

因此,现在" in"类型映射实际上根本不接受来自Python的任何输入。可以将其视为简单地准备本机调用的输入。

顺便说一句,您可以通过在其中使用noblock=1来避免SWIG应用的名称处理(以无法在同一函数上多次使用同一类型图或具有名称冲突的另一个类型图为代价)"输入"类型映射。我不建议这样做。

非固定数组长度?

最后值得一提的是,我们可以将所有这些类型图编写成更通用的形式,并适用于任何固定大小的数组。为此,我们在类型映射匹配中将2更改为" ANY",然后在类型映射主体内使用$1_dim0而不是2,因此,整个接口的末尾变为:

%module test

%{

#include"test.h"

%}

%typemap(in,numinputs=0) int[ANY] (int temp[$1_dim0]) {

//"In" typemap goes here:

memset(temp, 0, sizeof temp);

$1 = temp;

}

%typemap(argout) int[ANY] {

//"argout" goes here:

PyObject *list = PyList_New($1_dim0);

for (size_t i = 0; i < $1_dim0; ++i) {

PyList_SetItem(list, i, PyInt_FromLong(temp$argnum[i]));

}

$result = list;

}

%include"test.h"

哇,这太神奇了。 我必须转到执行此操作的另一台计算机上,然后我将使用您所说的内容。 我确实发现自己在" argout"类型映射中添加" in"类型映射可以部分解决问题-SWIG接受参数,但尚未正确处理该参数,但至少不再存在初始错误消息。

很好,您的建议很棒,很有启发性,但是,但是,如果我按照您的要求做,那么我还有另一个问题,我的包装是非法的。 请参阅其他问题stackoverflow.com/questions/21422148/

对于最后一个argout,我想对返回值做一个元组,所以不是$ result = list而是添加$ result = SWIG_Python_AppendOutput($ result,list);。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值