使对象的C++数组在Python中可迭代

Make C++ array of objects iterable in Python

本文关键字:Python 迭代 数组 对象 C++      更新时间:2023-10-16

我在网上搜索过,但没有成功。我将下面的示例代码封装到Python中(使用SWIG):

class atomo {
public:
    int i;
    atomo(int a) {
        i = a;
    };      
};
class funa {
public:
    atomo *lista[3];
    funa() {
        lista[0] = new atomo(1);
        lista[1] = new atomo(2);
        lista[2] = new atomo(3);
    };
};

但是Python不能使用comands 迭代或访问lista

>>> test = myModule.funa()
>>> test.lista[0]
      Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 6, in __iter__
      TypeError: 'SwigPyObject' object is not subscriptable
>>> for i in test.lista:
>>>     print(i)
      Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 6, in __iter__
      TypeError: 'SwigPyObject' object is not subscriptable

如何使lista可迭代?有没有一种方法可以使用Python列表而不是C++数组?

我的Python版本是3.2,我使用的是带有g++4.6.1 的SWIG 2.0.4

感谢

从您的问题中可以看出,您是否想要使用std::vector或您自己类型的数组。

对于std::vector,给定一些C++类:

#include <vector>
#include <string>
struct foo {
  std::string name;
};
inline std::vector<foo> test() {
  std::vector<foo> ret;
  foo instance;
  instance.name = "one";
  ret.push_back(instance);
  instance.name = "two";
  ret.push_back(instance);
  return ret;
}

您可以用%templatepyabc.istd_vector.i包装它,例如:

%module test
%{
#include "test.h"
%}
%include "pyabc.i"
%include "std_vector.i"
%include "test.h"
%template (FooVector) std::vector<foo>;

其将在Python类型上直观地表现。你需要打电话给SWIG,告诉他们:

swig-python-c++-py3-外部测试.i

如果这个想法是包装一个"自定义"容器,以便在Python方面直观地表现,我在前面的回答中给出了一个详细的例子。

为了简单起见,您可能希望在Python端而不是C++/SWIG端解决此问题。

# wrapper/facade
class Funa:
    def __init__(self):
        self._impl = myModule.funa()   # _impl => implementation
    def __iter__(self):
        for i in xrange(3):
            yield self._impl.lista[i]
test = Funa()
for x in test:
    print(x)

类似于larsmans的方法是让Funa.__iter__返回生成器对象。然后您只需要将其添加到SWIG创建的接口中。(用他的包装,你必须用其他方法包装,或者玩__getattr__。)大致上就像这个

class Funa:
  class FunaIter :
    def __init__(self, parent) :
      self.parent = parent
      self.pos = 0
    def __iter__(self) :
      while self.pos < 3 :
        yield self.parent.lista[self.pos]
        self.pos += 1
  def __iter__(self) :
    return self.FunaIter(self)

使用%extend%pythoncode指令将其插入SWIG文件应该更简单。

此外,SWIG有STL容器的包装器,所以也许使用这些包装器,您可以轻松地获得必要的项目getter。