如何制作更具表现力的python迭代器?就像c ++迭代器一样

5 c++ python iterator for-loop

首先,我快速查看c ++样式迭代器.例如:

//--- Iterating over vector with iterator.
vector<int> v;
. . .
for (vector<int>::iterator it = v.begin(); it!=v.end(); ++it) {
    cout << *it << endl;
}
Run Code Online (Sandbox Code Playgroud)

它很灵活.很容易改变底层容器类型.例如,您可能稍后决定插入和删除的数量是如此之高,以至于列表比向量更有效.它还有许多有用的成员函数.向量的许多成员函数使用迭代器,例如,赋值,插入或擦除.此外,我们可以使用双向性(如果支持)bidirectionaly,例如++, - .这对于解析像对象这样的流非常有用.

python的问题是:1:目前,python for循环语法的灵活性不如c ++ for.(嗯,更安全)2:而不是"it!= iter.end()"样式,当next()不再有时,python将抛出异常.它不灵活.

问题1:我的想法是否正确?

好.这是我的问题,如何实现像c ++迭代器一样强大的更强大的python迭代器?目前,python for循环语法不如c ++灵活.我还找到了一些可能的解决方案,例如http://www.velocityreviews.com/forums/t684406-pushback-iterator.html.但它要求用户推送一个东西而不是问迭代器 - .

问题2:在python中实现双向迭代器的最佳方法是什么?就像http://www.cplusplus.com/reference/std/iterator/BidirectionalIterator/一样.伪代码如下:

it = v.begin();
while( it!=v.end()) {
    //do sth here

    if (condition1)
        ++it;//suppose this iterator supports ++
    if(condition2)
      --it;//suppose this iterator supports --
}
Run Code Online (Sandbox Code Playgroud)

主要特点是:1)双向,2)更简单的"结束"检查."++"或" - "运算符或常用函数无关紧要(无论如何都没有语义差异).

谢谢,

更新:我从答案中得到了一些可能的解决方案:

i = 0
while i < len(sequence): # or i < len and some_other_condition
    star_it = sequence[i]
    if condition_one(star_it):
        i += 1
    if condition_two(star_it):
        i = max(i - 1, 0)
Run Code Online (Sandbox Code Playgroud)

但是,与数组不同,列表的随机访问应该是O(n).我想python内部的"list"对象是使用链接列表之类的东西实现的.因此,这种while循环解决方案效率不高.但是,在c ++中,我们有"随机迭代器","双向迭代器".我该如何获得更好的解决方案?谢谢.

agf*_*agf 5

对于大多数情况,Python for和迭代器是最简单的事情.这是他们的目标,他们不应该为了灵活性而妥协 - 他们缺乏灵活性不是问题.

对于一些无法使用for循环的情况,C++迭代器可能更简单.但总有一个办法做到这一点在Python不是太大比使用C++迭代器更复杂.


如果你需要将迭代器与循环分开,只需使用while循环:

it = iter(obj)

try:
    while True: # or some secondary break condition other than StopIteration
        star_it = next(it)
        if condition_one(star_it):
            star_it = next(it)
except StopIteration:
    pass # exhausted the iterator
Run Code Online (Sandbox Code Playgroud)

我只能想到两种--it在Python中有意义的情况.

首先是你在迭代一个序列.在这种情况下,如果你需要向后,根本不要使用迭代器 - 只需使用带while循环的计数器:

i = 0
while i < len(sequence): # or i < len and some_other_condition
    star_it = sequence[i]
    if condition_one(star_it):
        i += 1
    if condition_two(star_it):
        i = max(i - 1, 0)
Run Code Online (Sandbox Code Playgroud)

第二个是如果你正在迭代一个双向链表.在这种情况下,再次,不要使用迭代器 - 只是正常遍历节点:

current = node
while current: # or any break condition
    if condition_one(current):
        current = current.next
    if condition_two(star_it):
        current = current.prev
Run Code Online (Sandbox Code Playgroud)

可能认为它有意义但你不能使用上述任何一种方法的情况是使用像setor或者这样的无序集合dict.但是,在这种情况下--it 没有意义.由于集合在语义上是无序的,因此先前到达的任何项目都是合适的 - 而不仅仅是实际的先前项目.

因此,为了知道要返回的正确对象,您需要通过迭代像mydict.values()或者tuple(myset)使用计数器的序列,或者通过组合一系列先前的值并使用while循环next来代替上面的内存.一个for循环.

  • @XinlinCao:你的用例太模糊了.给出一个具体的实际用例,我们可以向您展示Python的一个很好的解决方案. (2认同)

Mat*_* M. 0

事实上,C++迭代器系统并没有那么伟大。迭代器类似于指针,但它们也有自己的缺点:

  • 奇异值:v.end()无法安全地取消引用
  • 反转问题:std::for_each(end, begin, func);
  • 不匹配问题:std::for_each(v0.begin(), v2.end(), func);

Python 方法在这方面要好得多(尽管异常的使用一开始可能会非常令人惊讶,但它确实有助于定义嵌套迭代器),因为与它的名称相反,Python 迭代器更类似于Range.

的概念Range比 C++11 引入的 range-for 循环结构好得多:

for (Object& o: range) {
}
Run Code Online (Sandbox Code Playgroud)

迭代器可以实现的任何功能也可以通过范围实现,尽管可能需要一些时间才能实现这一点,而且对于我们这些受过类似 C++ 指针迭代器教育的人来说,某些翻译一开始似乎是超现实主义的。例如,子范围可以完美地表达:

for (Object& o: slice(range, 2, 9)) {
}
Run Code Online (Sandbox Code Playgroud)

whereslice会将所有元素放在[2, 9)内的位置range

因此,与其与你的语言 (Python) 作斗争,不如进一步深入研究它并接受它的风格。与一种语言作斗争通常是一场失败的战斗,学习它的习语,变得更有效率。