代码之家  ›  专栏  ›  技术社区  ›  Stanley Wang

Python-typemap中的SWIG不起作用

  •  4
  • Stanley Wang  · 技术社区  · 6 年前

    我正在学习将c++代码包装到Python模块中,对于以下函数需要typemap int foo(int argc, char **argv); 例如,一个简单的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;
        $1 = PyList_Size($input);
        $2 = (char **) malloc(($1+1)*sizeof(char *));
        for (i = 0; i < $1; i++) {
          PyObject *o = PyList_GetItem($input,i);
          if (PyString_Check(o))
        $2[i] = PyString_AsString(PyList_GetItem($input,i));
          else {
        PyErr_SetString(PyExc_TypeError,"list must contain strings");
        free($2);
        return NULL;
          }
        }
        $2[i] = 0;
      } else {
        PyErr_SetString(PyExc_TypeError,"not a list");
        return NULL;
      }
    }
    
    %typemap(freearg) (int argc, char **argv) {
      free((char *) $2);
    }
    
    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
    

    在typemap中似乎 $input 确实作为Python列表收到,但出现了一些问题 PyList_GetItem($input,i) . 我做错什么了吗?

    提前感谢!

    2 回复  |  直到 6 年前
        1
  •  2
  •   Davis Herring    6 年前

    字节与字符

    基本问题是Python3字符串 性格 字符串,而普通Python 2字符串和 char* 字节 串。( char字符* 通常也被视为以null结尾。)像这样的 PyString_Check 已在Python3中删除,您必须以某种方式处理编码。

    如果你想接受Python3 str 对象,使用 PyUnicode 用于检查和编码参数的函数。否则,通过 bytes Python中的对象: bytes literals 对于固定ASCII字符串(如 Args.foo([b"foo",b"bar",b"spam",b"1"]) ),或者 str.encode .

    代码为何编译

    SWIG生成的包装器代码与兼容 Python 2 or 3 . 即使有 -py3 ,它是以Python2样式编写的,由许多兼容宏(来自 pyhead.swg ):

    #if PY_VERSION_HEX >= 0x03000000
    
    /* ... */
    #define PyString_Check(name) PyBytes_Check(name)
    /* ... */
    
    #endif
    

    在现代世界,大多数是-3世界,使用SWIG可能更可取 bytesobject.h 相反它以另一种方式定义同义词,使字节字符串显而易见。

        2
  •  0
  •   Loftx    6 年前

    我在谷歌搜索时发现了这个问题,在那里我收到了相同的错误

    TypeError: list must contain strings
    

    由于该错误仅在升级到Python 3后出现,因此我可以通过以下更改来解决它

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

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