Python - 类型图中的 SWIG 不起作用

Python - SWIG in typemap does not work

我正在学习将c++代码包装到Python模块中,像int foo(int argc, char **argv);这样的函数需要typemap 例如,一个简单的c++代码可以是

#include <iostream>

int foo(int argc, char** argv) {
    std::cout << "Have " << argc << " arguments:" << std::endl;
    for (int i = 0; i < argc; ++i) {
        std::cout << argv[i] << std::endl;
    }
    return 0;
}

然后我按照SWIG教程here(34.9.2)写了SWIG的接口文件:

%module Args
%{
extern int foo(int argc, char **argv);
%}

%typemap(in) (int argc, char **argv) {
  /* Check if is a list */
  if (PyList_Check($input)) {
    int i;
     = PyList_Size($input);
     = (char **) malloc((+1)*sizeof(char *));
    for (i = 0; i < ; i++) {
      PyObject *o = PyList_GetItem($input,i);
      if (PyString_Check(o))
    [i] = PyString_AsString(PyList_GetItem($input,i));
      else {
    PyErr_SetString(PyExc_TypeError,"list must contain strings");
    free();
    return NULL;
      }
    }
    [i] = 0;
  } else {
    PyErr_SetString(PyExc_TypeError,"not a list");
    return NULL;
  }
}

%typemap(freearg) (int argc, char **argv) {
  free((char *) );
}

extern int foo(int argc, char **argv);

但是构建模块后,总是报错Python:

>>> import Args
>>> Args.foo(["foo","bar","spam","1"])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: list must contain strings

在类型图中,似乎 $input 确实被接收为 Python 列表,但 PyList_GetItem($input,i) 出了点问题。我是不是做错了什么?

提前致谢!

字节与字符

根本问题是 Python 3 字符串是 字符 字符串,而普通 Python 2 字符串和 char*byte 个字符串。 (char* 通常也被认为是空终止的。)因此,PyString_Check 已在 Python 3 中删除,您必须以某种方式处理编码。

如果您想接受 Python 3 str 个对象,请使用 PyUnicode 函数来检查和编码参数。否则,从 Python 传递 bytes 个对象:bytes literals for fixed ASCII strings (like Args.foo([b"foo",b"bar",b"spam",b"1"])), or else the result of str.encode.

为什么代码可以编译

SWIG 生成的包装器代码与 Python 2 or 3 兼容。 即使使用 -py3,它也是以 Python 2 风格编写的,由许多兼容性宏(来自 pyhead.swg)支持:

#if PY_VERSION_HEX >= 0x03000000

/* ... */
#define PyString_Check(name) PyBytes_Check(name)
/* ... */

#endif

在现代的、主要是 3 的世界中,SWIG 最好使用 bytesobject.h。它以另一种方式定义同义词,使字节串显而易见。

我发现这个问题是 google 搜索的结果,我收到了同样的错误

TypeError: list must contain strings

由于升级到 Python 3 后才出现错误,我可以通过以下更改解决它

Args.foo([b"foo",n"bar",b"spam",b"1"])

b 强制 Python 将字符串作为 Python2 字节字符串而不是 Python3 unicode 字符串发送,以防这对其他人有帮助。