如何在Python中将swig矩阵对象转换为字符串

5 投票
2 回答
2932 浏览
提问于 2025-04-15 21:03

我正在使用 openbabel 的 swig 封装(这个是用 C++ 写的,通过 swig 提供了一个 Python 的接口)。

下面我只是用它来读取一个分子结构文件,并获取它的单位晶胞属性。

import pybel
for molecule in pybel.readfile('pdb','./test.pdb'):
    unitcell = molecule.unitcell
    print unitcell
   |..>     
   |..>     
<openbabel.OBUnitCell; proxy of <Swig Object of type 'OpenBabel::OBUnitCell *' at 0x17b390c0> >

单位晶胞有一个叫 CellMatrix() 的函数,

unitcell.GetCellMatrix()
   <22> <openbabel.matrix3x3; proxy of <Swig Object of type 'OpenBabel::matrix3x3 *' at 0x17b3ecf0> >

OpenBabel::matrix3x3 大概是这样的:

1 2 3
4 5 6
7 8 9

我想知道怎么打印出这个 matrix3x3 的内容。我试过用 __str____repr__

有没有什么通用的方法可以把用 swig 封装的矩阵内容转成字符串在 Python 中显示出来?

谢谢!

2 个回答

1

接着@jhoon的回答,SWIG似乎不识别std::string这种返回类型,所以你需要把函数改成返回const char*。另外,因为这个函数是在类外部的,你不能用self,而是要用SWIG的$self变量。

所以,在SWIG的.i文件中,如果你写下以下内容:

%extend OpenBabel::matrix3x3 {
  const char* __str__() {
    std::ostringstream out;
    out << *$self;
    return out.str().c_str();
  }
};

当你在Python中打印matrix3x3的时候,就应该能得到想要的结果。

如果你发现自己需要在很多类中添加这个,考虑把它封装成一个宏,比如:

%define __STR__()
const char* __str__() {
  std::ostringstream out;
  out << *$self;
  return out.str().c_str();
}
%enddef

然后再用以下方式把它添加到类中:

%extend OpenBabel::matrix3x3 {
  __STR__()
};
5

根据这个openbabel的文档,Python的绑定没有提供一个好方法来打印matrix3x3对象,是有原因的。matrix3x3这个C++类重载了<<运算符,但SWIG会直接忽略这个运算符。

http://openbabel.org/api/2.2.0/classOpenBabel_1_1matrix3x3.shtml

这意味着你需要修改你的SWIG接口文件(可以查看http://www.swig.org/Doc1.3/SWIGPlus.html#SWIGPlus_class_extension),为C++中的openbabel::matrix3x3添加一个__str__方法,这个方法会包装<<运算符。你的方法可能看起来像这样:

std::string __str__() {
  //make sure you include sstream in the SWIG interface file
  std::ostringstream oss(std::ostringstream::out);
  oss << (*this);
  return oss.str();
}

我相信在这种情况下,SWIG会正确处理C++的返回类型std::string,但如果不行,你可能需要尝试返回一个字符数组。

到这一步,你应该能够重新编译绑定,并重新运行你的Python代码。调用str()matrix3x3对象上,现在应该能显示出在C++中用<<运算符显示的内容。

撰写回答