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

Posted

技术标签:

【中文标题】Python - 类型图中的 SWIG 不起作用【英文标题】:Python - SWIG in typemap does not work 【发布时间】:2018-01-22 23:32:49 【问题描述】:

我正在学习将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;
    $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

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

提前致谢!

【问题讨论】:

水晶球在工作:这是 Python 3 吗? 是的。我使用 Python 3.6.1 【参考方案1】:

字节与字符

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

如果您想接受 Python 3 str 对象,请使用 PyUnicode 函数来检查和编码参数。否则,从 Python 传递 bytes 对象:bytes literals 用于固定的 ASCII 字符串(如 Args.foo([b"foo",b"bar",b"spam",b"1"])),否则为 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。它以另一种方式定义同义词,使字节串明显。

【讨论】:

感谢您的出色解释。没有意识到 Python 3 的问题。将PyString 更改为PyUnicode_AsUTF8 确实有效!【参考方案2】:

我通过谷歌搜索发现了这个问题,我收到了同样的错误

TypeError: list must contain strings

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

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

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

【讨论】:

以上是关于Python - 类型图中的 SWIG 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

图形文本标签在折线图中不起作用 python

SWIG Python 未定义符号错误

带有 swig 的模块名称

如何使用 Swig 中止调用 C 函数的 Python 脚本?

AnyLogic - 为啥我的基于条件的转换不起作用?

当我慢慢画线时,图中的虚线不起作用