如何跨 swig 类型映射重用代码?
How can I reuse code across swig typemaps?
我有两个 swig 类型映射,里面有一堆重复的代码。我想合并代码如下:
%{
#include "structure_defs.h"
%}
%ignore Cartesian2PyList(const schrodinger::Cartesian&);
PyObject* Cartesian2PyList(const schrodinger::Cartesian& cartesian)
{
PyObject *o;
o = PyList_New(3);
PyObject* item = PyFloat_FromDouble(cartesian.x);
PyList_SetItem(o, 0, item);
item = PyFloat_FromDouble(cartesian.y);
PyList_SetItem(o, 1, item);
item = PyFloat_FromDouble(cartesian.z);
PyList_SetItem(o, 2, item);
return o;
}
%typemap(out) schrodinger::Cartesian
{
$result = Cartesian2PyList();
}
%typemap(out) std::vector<schrodinger::Cartesian>
{
PyObject *o;
o = PyList_New(.size());
for (uint i=0; i<.size(); i++) {
PyObject *elem = Cartesian2PyList(.at(i));
PyList_SetItem(o, i, elem);
}
$result = o;
}
%include "cartesian.h"
但是,编译失败,因为在编译时找不到Cartesian2PyList 的定义。在多个类型映射中重用代码的最佳方式是什么?
您可以使用 %{ %}
将代码直接传递到生成的 .c 文件。因此,在包装器中重用代码的最简单方法是将其放入包装器中,可能作为静态函数,这样它就不会与同一模块中的其他任何东西发生冲突。在您的示例中,这将起作用:
%{
#include "structure_defs.h"
%}
%{
static PyObject* Cartesian2PyList(const schrodinger::Cartesian& cartesian)
{
PyObject *o;
o = PyList_New(3);
PyObject* item = PyFloat_FromDouble(cartesian.x);
PyList_SetItem(o, 0, item);
item = PyFloat_FromDouble(cartesian.y);
PyList_SetItem(o, 1, item);
item = PyFloat_FromDouble(cartesian.z);
PyList_SetItem(o, 2, item);
return o;
}
%}
%typemap(out) schrodinger::Cartesian
{
$result = Cartesian2PyList();
}
%typemap(out) std::vector<schrodinger::Cartesian>
{
PyObject *o;
o = PyList_New(.size());
for (uint i=0; i<.size(); i++) {
PyObject *elem = Cartesian2PyList(.at(i));
PyList_SetItem(o, i, elem);
}
$result = o;
}
%include "cartesian.h"
如果您愿意,可以在此处将两个 %{ %}
块合并为一个块。
我还删除了那里的 %ignore
指令,因为 %{ %}
中的代码只是输出到生成的模块中而不是包装,所以会是多余的。另一方面,如果您确实希望在生成的代码中对其进行包装和定义,您可以使用 %inline %{ ... %}
,例如:
%inline %{
static PyObject* Cartesian2PyList(const schrodinger::Cartesian& cartesian)
{
//...
}
%}
如果您编写的是更通用的 SWIG 代码而不是单个模块,则可以使用更智能的东西,请参阅 fragments, %define
and $typemap
。在简单的情况下,尽管只编写如上所示的模块内部使用的代码就足够了。
我有两个 swig 类型映射,里面有一堆重复的代码。我想合并代码如下:
%{
#include "structure_defs.h"
%}
%ignore Cartesian2PyList(const schrodinger::Cartesian&);
PyObject* Cartesian2PyList(const schrodinger::Cartesian& cartesian)
{
PyObject *o;
o = PyList_New(3);
PyObject* item = PyFloat_FromDouble(cartesian.x);
PyList_SetItem(o, 0, item);
item = PyFloat_FromDouble(cartesian.y);
PyList_SetItem(o, 1, item);
item = PyFloat_FromDouble(cartesian.z);
PyList_SetItem(o, 2, item);
return o;
}
%typemap(out) schrodinger::Cartesian
{
$result = Cartesian2PyList();
}
%typemap(out) std::vector<schrodinger::Cartesian>
{
PyObject *o;
o = PyList_New(.size());
for (uint i=0; i<.size(); i++) {
PyObject *elem = Cartesian2PyList(.at(i));
PyList_SetItem(o, i, elem);
}
$result = o;
}
%include "cartesian.h"
但是,编译失败,因为在编译时找不到Cartesian2PyList 的定义。在多个类型映射中重用代码的最佳方式是什么?
您可以使用 %{ %}
将代码直接传递到生成的 .c 文件。因此,在包装器中重用代码的最简单方法是将其放入包装器中,可能作为静态函数,这样它就不会与同一模块中的其他任何东西发生冲突。在您的示例中,这将起作用:
%{
#include "structure_defs.h"
%}
%{
static PyObject* Cartesian2PyList(const schrodinger::Cartesian& cartesian)
{
PyObject *o;
o = PyList_New(3);
PyObject* item = PyFloat_FromDouble(cartesian.x);
PyList_SetItem(o, 0, item);
item = PyFloat_FromDouble(cartesian.y);
PyList_SetItem(o, 1, item);
item = PyFloat_FromDouble(cartesian.z);
PyList_SetItem(o, 2, item);
return o;
}
%}
%typemap(out) schrodinger::Cartesian
{
$result = Cartesian2PyList();
}
%typemap(out) std::vector<schrodinger::Cartesian>
{
PyObject *o;
o = PyList_New(.size());
for (uint i=0; i<.size(); i++) {
PyObject *elem = Cartesian2PyList(.at(i));
PyList_SetItem(o, i, elem);
}
$result = o;
}
%include "cartesian.h"
如果您愿意,可以在此处将两个 %{ %}
块合并为一个块。
我还删除了那里的 %ignore
指令,因为 %{ %}
中的代码只是输出到生成的模块中而不是包装,所以会是多余的。另一方面,如果您确实希望在生成的代码中对其进行包装和定义,您可以使用 %inline %{ ... %}
,例如:
%inline %{
static PyObject* Cartesian2PyList(const schrodinger::Cartesian& cartesian)
{
//...
}
%}
如果您编写的是更通用的 SWIG 代码而不是单个模块,则可以使用更智能的东西,请参阅 fragments, %define
and $typemap
。在简单的情况下,尽管只编写如上所示的模块内部使用的代码就足够了。