如何使用SWIG使Python可以迭代C ++类?

时间:2016-02-09 11:36:08

标签: python c++ iterator swig

我有一个C ++类Collection来管理std::vector<Element>(该类的私有成员)。

从C ++我可以使用begin()end()迭代器(它们只是vector迭代器的typedef)遍历向量,如:

Collection col;
for (Collection::const_iterator itr = col.begin(); itr != col.end(); itr++)
{
  std::cout << itr->get() << std::endl;
}

现在我希望用Python做类似的事情:

import example
el = example.Element()
el.set(5)
col = example.Collection()
col.add(el)
for e in col:
    print e.get()

但结果是:

  

TypeError:&#39; Collection&#39;对象不可迭代

我无法以一种方式配置SWIG,因为它为Python __iter__类生成Collection(我认为它是唯一需要的东西)。我该怎么做?

这是我的代码:

example.h文件:

#include <vector>

class Element
{
public:
  Element();
  ~Element();

  int get() const;
  void set(const int var);

private:
  int variable_;
};

class Collection
{
public:
  Collection();
  ~Collection();

  void add(const Element& element);

  typedef std::vector<Element> tElements;

  // iterators
  typedef tElements::iterator iterator;
  typedef tElements::const_iterator const_iterator;
  iterator begin();
  const_iterator begin() const;
  iterator end();
  const_iterator end() const;

private:
  tElements          elements_;
};

example.cpp:

#include "example.h"

Element::Element() {}

Element::~Element() {}

int Element::get() const
{
  return variable_;
}

void Element::set(const int var)
{
  variable_ = var;
}

Collection::Collection() : elements_() {}

Collection::~Collection() {}

void Collection::add(const Element& element)
{
  elements_.push_back(element);
}

Collection::iterator Collection::begin()
{
  return elements_.begin();
}

Collection::const_iterator Collection::begin() const
{
  return elements_.begin();
}

Collection::iterator Collection::end()
{
  return elements_.end();
}

Collection::const_iterator Collection::end() const
{
  return elements_.end();
}

example.i:

%module example
%{
#include "example.h"
%}

// I've tried to add this, but that generates a whole
// other class, that is not what I want.
// %include "std_vector.i"
// %template(ElementVector) std::vector<Element>;

// I've also tried to %extend the class (which I think is what I want,
// but I cannot figure out with what to extend it with)

// Include the header file with above prototypes
%include "example.h"

编译:

swig -python -c++ -o example_wrap.cpp example.i
g++ -fPIC -c example.cpp example_wrap.cpp -I/usr/include/python2.6
g++ -shared example.o example_wrap.o -o _example.so

1 个答案:

答案 0 :(得分:3)

受到最后一个例子的启发:https://stackoverflow.com/a/8828454/3613373。我提出了一种稍微不同的方法,它不使用变量来检查StopIterator异常状态。

此外,它仅使用begin()的{​​{1}}结束end()迭代器,而不需要公开(Collection} public本身。

example.i:

std::vector<Element>

我唯一想通知的是如何创建%module example %{ #include "example.h" %} %inline %{ class StopIterator {}; class Iterator { public: Iterator(Collection::iterator _cur, Collection::iterator _end) : cur(_cur), end(_end) {} Iterator* __iter__() { return this; } Collection::iterator cur; Collection::iterator end; }; %} %include "example.h" %include "exception.i" %exception Iterator::next { try { $action // calls %extend function next() below } catch (StopIterator) { PyErr_SetString(PyExc_StopIteration, "End of iterator"); return NULL; } } %extend Iterator { Element& next() { if ($self->cur != $self->end) { // dereference the iterator and return reference to the object, // after that it increments the iterator return *$self->cur++; } throw StopIterator(); } } %extend Collection { Iterator __iter__() { // return a constructed Iterator object return Iterator($self->begin(), $self->end()); } }; 的模板化版本,我只能传递任何Iterator,而无需为每个模板即时重新定义Iterator<Collection, Element> 。欢迎解决方案;)