- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
研究如何使用 swig 在 Python 中很好地包装枚举,我遇到了 this回答。
我正在尝试创建这样的枚举:
#ifndef PYTHON_ENUM
#define PYTHON_ENUM(x) enum x
#endif
PYTHON_ENUM(TestName) {
foo=1,
bar=2
};
PYTHON_ENUM(SomeOtherName) {
woof,
moo
};
我这样使用 .i 文件
%module test
%{
#include "test.h"
%}
%typemap(constcode) int {
PyObject *val = PyInt_FromLong(($type)($value));
SWIG_Python_SetConstant(d, "$1", val);
const char *name = "$typemap(enum_realname,$1_type)";
PyObject *e = PyDict_GetItemString(d, name);
if (!e) PyDict_SetItemString(d, name, e = PyDict_New());
PyDict_SetItemString(e, "$value", val);
}
#define PYTHON_ENUM(x) \
%typemap(enum_realname) int "x"; \
%pythoncode %{ \
x = _test.x\
%} \
enum x
%include "test.h"
问题是这会抛出 AttributeError: module '_test' has no attribute 'TestName'这源于这样一个事实,即生成的 test.py 定义了 TestName 字典:
TestName = _test.testEnum # This should be in the last line
_test.foo_swigconstant(_test)
foo = _test.foo
_test.bar_swigconstant(_test)
bar = _test.bar
在调用 TestName = _test.testEnum
时,_test 没有 testEnum
成员并抛出异常。一旦 foo_swigconstant()
或 bar_swigconstant()
运行,就会生成 _test.testEnum
并且 TestName = _test.testEnum
不会失败。因此,这一行应该在枚举值注册之后。如果我手动执行它会起作用,但每次 SWIG 运行时我都必须这样做,这有点麻烦。其他枚举也是如此。我可以更改接口(interface)文件以适应这种情况吗?
最佳答案
我没有看到这个错误。我编译并链接示例如下:
swig3.0 -c++ -python test.i
g++ -c -fPIC test_wrap.cxx -I/usr/include/python2.7
g++ -shared -g test_wrap.o -o _test.so
然后它就完全按照 Flexo 的建议工作了。请注意,生成的 test.py 和 _test.so 位于同一目录中。我在 Debian 下使用 Python 2.7.6 和 SWIG 3.0.7。
我使用 VS2013 和 SWIG 3.0.8 进行了同样的尝试。发生的事情是 typemap(constcode)
生成函数 woof_swigconstant
等,而不是插入 const 代码,它只是暴露静态字典。您使用 SWIG 3.0.7 尝试过吗?
我对此进行了更深入的研究。使用 SWIG 3.0.8 和 VS2013。生成的代码例如foo 条目是:
SWIGINTERN PyObject *foo_swigconstant(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
PyObject *module;
PyObject *d;
if (!PyArg_ParseTuple(args,(char*)"O:swigconstant", &module)) return NULL;
d = PyModule_GetDict(module);
if (!d) return NULL;
{
PyObject *val = PyInt_FromLong((int)(foo));
SWIG_Python_SetConstant(d, "foo", val);
const char *name = "TestName";
PyObject *e = PyDict_GetItemString(d, name);
if (!e) PyDict_SetItemString(d, name, e = PyDict_New());
PyDict_SetItemString(e, "foo", val);
}
return SWIG_Py_Void();
}
至此,一个函数入口就生成了。在 Debian 上使用 SWIG 3.0.7 和 Python 2.7.6,我得到以下结果
{
PyObject *val = PyInt_FromLong((int)(foo));
SWIG_Python_SetConstant(d, "foo", val);
const char *name = "TestName";
PyObject *e = PyDict_GetItemString(d, name);
if (!e) PyDict_SetItemString(d, name, e = PyDict_New());
PyDict_SetItemString(e, "foo", val);
}
在 SWIG_InstallConstants(d,swig_const_table);
之后立即插入。我相信从 SWIG 3.0.7 到 3.0.8 发生了一些变化。
关于python - Python 后续中的 SWIG 枚举创建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37141526/
我是一名优秀的程序员,十分优秀!