SWIG和Python:如何将手动创建的类添加到SWIG生成的模块中?

时间:2016-12-29 22:05:14

标签: python swig

我的project使用SWIG在一个名为tensorflow.python.pywrap_tensorflow的模块中自动为一组C ++函数和类型创建包装器。我想直接使用Python C API定义一个新类型,并将其添加到该模块。 (特别是,我想定义一个实现Python buffer protocol的新类型,以便我可以将本机缓冲区公开为memoryview。)

我可以通过在.i文件中内联来为我的新类型定义必需的结构:

%{

typedef struct {
  PyObject_HEAD
  /* Other fields... */
} MyType;

// Define functions for the initializer, destructor, and buffer protocol:
// * MyType_init
// * MyType_dealloc
// * MyType_old_getbuffer (the readbufferproc for Python 2.7)
// * MyType_segcount (for Python 2.7)
// * MyType_getbuffer (the Python 2.7/3.x buffer protocol)

// ...

static PyBufferProcs MyType_as_buffer = {
#if PY_VERSION_HEX < 0x03000000
  (readbufferproc)MyType_old_getbuffer,
  (writebufferproc)0,
  (segcountproc)MyType_segcount,
  (charbufferproc)0,
#endif
  (getbufferproc)MyType_getbuffer,
  (releasebufferproc)0,
};

static PyTypeObject MyType_TypeObject = {
  /* PyObject header changed in Python 3 */
#if PY_VERSION_HEX>=0x03000000
  PyVarObject_HEAD_INIT(NULL, 0)
#else
  PyObject_HEAD_INIT(NULL)
  0 /* ob_size */,
#endif
  "MyType" /* tp_name */,
  sizeof(MyType) /* tp_basicsize */,
  0 /* tp_itemsize */,
  (destructor)MyType_dealloc /* tp_dealloc */,
  0 /* tp_print */,
  0 /* tp_getattr */,
  0 /* tp_setattr */,
#if PY_VERSION_HEX>=0x03000000
  0 /* tp_reserved in 3.0.1 */
#else
  0 /* tp_compare */,
#endif
  0 /* tp_repr */,
  0 /* tp_as_number */,
  0 /* tp_as_sequence */,
  0 /* tp_as_mapping */,
  0 /* tp_hash */,
  0 /* tp_call */,
  0 /* tp_str */,
  0 /* tp_getattro */,
  0 /* tp_setattro */,
  &MyType_as_buffer /* tp_as_buffer */,
  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_NEWBUFFER /* tp_flags */,
  "Python wrapper for MyType." /* tp_doc */,
  0 /* tp_traverse */,
  0 /* tp_clear */,
  0 /* tp_richcompare */,
  0 /* tp_weaklistoffset */,
  0 /* tp_iter */,
  0 /* tp_iternext */,
  0 /* tp_methods */,
  0 /* tp_members */,
  0 /* tp_getset */,
  0 /* tp_base */,
  0 /* tp_dict */,
  0 /* tp_descr_get */,
  0 /* tp_descr_set */,
  0 /* tp_dictoffset */,
  (initproc)MyType_init /* tp_init */,
};

%}

执行此操作后,我想通过调用PyModule_AddObject()将类型对象添加到SWIG生成的模块,可能是在模块初始化块(%init %{ ... %})中。但是,我不知道在创建tensorflow.python.pywrap_tensorflow模块的生成代码中,从Py_InitModule()(或Python 3.x中的PyModule_Create())返回的值会给出什么名称。我已经能够在%init %{ ... %}块中创建第二个模块,但如果可能的话,我更愿意将其添加到自动生成的模块中。

回答这两个问题都可以解决我的问题:

  • 是否有SWIG宏用于访问初始化块中生成的模块对象(例如,通过扩展到相应PyObject*的变量名称)?这个对象似乎存储在我生成的代码中名为m的局部变量中,但我不知道在所有发行版中是否保证相同。

  • 或者是否有更惯用的方法来实现我想要使用SWIG实现的目标?缓冲协议类型映射似乎来自他们的documentation似乎是为了编写接受缓冲区作为参数的函数而设计的,而我希望我的包装器类型实现缓冲区协议。

2 个答案:

答案 0 :(得分:0)

如果您正在编写自己的类或结构,swig将为它构建一个python类型,您所要做的就是添加插槽。尝试%功能(python:slot)。此功能可以让您向生成的python类型插槽添加任意函数/结构。还可以使用&#39; -builtin&#39;来构建.i文件选项,发出不必要的代理python文件。

答案 1 :(得分:0)

只是让Jacky的答案更明确-您可能想要做类似的事情:

%{
static *PyBuffer mycoolbuffer_function(PyObject* self) {
    // get the C data for self
    // build your buffer
}
%}

%feature("python:tp_as_buffer") MyTypeThatWillBeWrapped "&mycoolbuffer_function";

这是未经测试的,我从迭代器所做的一些工作中进行了类比。当然,它需要-builtin选项。