在C ++中,特别是STL,我们在任何地方都看到了迭代器。 Python也有迭代器,但这是两个非常不同的令人讨厌的东西。
C ++迭代器:
- C ++有5种类型(随机访问,双向,转发,输入,输出)
- 有两种操作类别:重新定位,访问
- 需要一对迭代器来表示(第一个/最后一个)范围。
Python迭代器:
- 1类(前进)
- 1个操作类别(next())
- 最后引发StopIteration异常
典型的Python迭代协议: for y in x...
如下:
iter = x.__iter__() # get iterator
try:
while 1:
y = iter.next() # get each item
... # process y
except StopIteration: pass # iterator exhausted
Boost.Python提供了一些机制来使C ++迭代器像Python迭代器一样很好地发挥作用。 我们需要做的是从与Python迭代协议兼容的C ++迭代器生成适当的__iter__
函数。 例如:
object get_iterator = iterator<vector<int> >();
object iter = get_iterator(v);
object first = iter.next();
或者在类_ <>中使用:
.def("__iter__", iterator<vector<int> >())
范围
我们可以使用range函数创建一个Python精明的迭代器:
- range(start, finish)
- range<Policies,Target>(start, finish)
在这里,开始/结束可能是以下之一:
- 成员数据指针
- 成员函数指针
- 自适应函数对象(使用Target参数)
迭代器
- iterator<T, Policies>()
给定一个容器T
,迭代器是一个简单的调用range
的快捷方式,使用&T :: begin,&T :: end。
让我们付诸行动......这是一个假设的bogon粒子加速器代码的例子:
f = Field()
for x in f.pions:
smash(x)
for y in f.bogons:
count(y)
现在,我们的C ++ Wrapper:
class_<F>("Field")
.property("pions", range(&F::p_begin, &F::p_end))
.property("bogons", range(&F::b_begin, &F::b_end));
stl_input_iterator
到目前为止,我们已经看到了如何将C ++迭代器和范围公开给Python。 有时我们希望采用另一种方式:我们希望将Python序列传递给STL算法或使用它来初始化STL容器。 我们需要使Python迭代器看起来像STL迭代器。 为此,我们使用stl_input_iterator <>
。 考虑一下我们如何实现一个将std :: list < int >:: assign ()
暴露给Python的函数:
template<typename T>
void list_assign(std::list<T>& l, object o) {
// Turn a Python sequence into an STL input range
stl_input_iterator<T> begin(o), end;
l.assign(begin, end);
}
// Part of the wrapper for list<int>
class_<std::list<int> >("list_int")
.def("assign", &list_assign<int>)
// ...
;
现在在Python中,我们可以为list_int
对象分配任何整数序列:
x = list_int();
x.assign([1,2,3,4,5])