怎么了?
简而言之,这些类型图不是一个或非命题。
您缺少的关键信息是多个类型映射协作包装单个函数的方式。
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时,会产生以下结果:
// ... <snip> arg1 = reinterpret_cast< Foobar * >(argp1); { // "In" typemap goes here } (arg1)->method(arg2); resultobj = SWIG_Py_Void(); { // "argout" goes here } return resultobj; // ... <snip>在那些类型映射中,“ 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”类型映射之前,在生成的代码中还需要注意一件事。生成的代码中的临时数组实际上看起来像
inttemp2[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用户提供将被忽略的列表是没有意义的。
我们可以通过修改“
in”类型映射来做到这一点,使用
numinputs=0表示不需要Python输入。您还需要在这里适当地初始化临时文件。现在,类型映射变得简单:
%typemap(in,numinputs=0) int[2] (int temp[2]) { // "In" typemap goes here: memset(temp, 0, sizeof temp); $1 = temp;}因此,现在“ in”类型映射实际上根本不接受来自Python的任何输入。可以将其视为简单地准备本机调用的输入。
顺便说一句,您可以避免在SWIG中应用名称混乱(因为无法在同一函数上多次使用同一类型图,或者使用另一个具有名称冲突的类型图)
noblock=1。
”类型图。我不建议这样做。
非固定数组长度?
最后值得一提的是,我们可以将所有这些类型图编写成更通用的形式,并适用于任何固定大小的数组。为此,我们在类型映射匹配中将2更改为“
ANY”,然后在类型映射
$1_dim0主体中使用2而不是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"


