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 字符串发送,以防这对其他人有帮助。
我正在学习将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 字符串发送,以防这对其他人有帮助。