在Python中创建SWIG枚举

SWIG enumeration creation in Python followup

本文关键字:SWIG 枚举 创建 Python      更新时间:2023-10-16

在研究如何使用swig在Python中很好地包装枚举时,我得到了这个答案。

我正在尝试创建这样的枚举:

#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:模块"_test"没有属性"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运行时我都必须这样做,这有点麻烦。其他枚举也是如此。我可以更改接口文件以适应它吗?

我没有看到这个错误。我编译并链接了如下示例:

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);
  }

紧接在CCD_ 9之后插入。我相信SWIG 3.0.7到3.0.8有些变化。