Pythonic相当于unshift或redo?

Bil*_*win 12 python redo

我正在学习Python,我有一种情况,我想从迭代器中使用项目.棘手的部分是在某些条件下,我想"不迭代".也就是说,在循环之前将项放回到迭代器的前面.

例如,假设我从树上摘苹果.我的水果篮在需要清空之前只能容纳10公斤.但是我必须在我称之前挑选每个苹果,并确定这个苹果是否会超过篮子的容量.

在像Perl这样的语言中,我可以unshift()将苹果重新放回树上,然后让循环表达式重新选择苹果:

while ($apple = shift(@tree)) {
  $wt = weight($apple);
  if ($wt + weight(@basket) > 10) {
    send(@basket);
    @basket = ();
    unshift(@tree, $apple);
  } else {
    push(@basket, $element);
  }
}
Run Code Online (Sandbox Code Playgroud)

或者我也可以使用redo,它在块的顶部恢复处理,而不评估循环表达式.因此,在篮子被清空后,同样的苹果可以被重新加工.

while ($apple = shift(@tree)) {
  $wt = weight($apple);
  if ($wt + weight(@basket) > 10) {
    send(@basket);
    @basket = ();
    redo;
  } else {
    push(@basket, $apple);
  }
}
Run Code Online (Sandbox Code Playgroud)

对于这类问题,什么是最pythonic的解决方案?

Fed*_*oni 16

我正在学习Python,我有一种情况,我想从迭代器中使用项目.棘手的部分是在某些条件下,我想"不迭代".也就是说,在循环之前将项放回到迭代器的前面.

这是一个简单的解决方案:

class MyIterator(object):   # undo-able iterator wrapper
    def __init__(self, iterable):
        super(MyIterator, self).__init__()
        self.iterator = iter(iterable)
        self.stack = []

    def __iter__(self):
        return self

    def next(self):
        if self.stack:
            return self.stack.pop()
        return self.iterator.next()  # Raises StopIteration eventually

    def undo(self, item):
        self.stack.append(item)
Run Code Online (Sandbox Code Playgroud)
for i in  MyIterator(xrange(5)): print i
0
1
2
3
4
Run Code Online (Sandbox Code Playgroud)
rng = MyIterator(xrange(5))
rng.next()
0
rng.next()
1
rng.undo(1)
rng.next()
1
Run Code Online (Sandbox Code Playgroud)


Pat*_*ick 13

当else子句总是应该出现时,为什么要烦恼呢?

for apple in tree:
    if (apple.weight + basket.weight) > 10:
       send(basket)
       basket.clear()
    basket.add(apple)
Run Code Online (Sandbox Code Playgroud)

无论如何,我很确定Python没有你想要的那种行为.


cdl*_*ary 6

我会说最Pythonic解决方案是最简单的解决方案.而不是试图将迭代器包装在允许你"回溯"或类似复杂的东西的生成器表达式中,使用while循环,就像在Perl中一样!迭代器不会与变异混合得非常好.

简单翻译您的实现(忽略@Patrick的优化):

while tree:
    apple = tree.pop(0)
    if apple.weight + basket.weight > 10:
        basket.send()
        basket.clear()
        tree.insert(0, apple) # Put it back.
    else:
        basket.append(apple)
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用peek具有有序序列索引的类似功能:

while tree:
    apple = tree[0] # Take a peek at it.
    if apple.weight + basket.weight > 10:
        basket.send()
        basket.clear()
    else:
        basket.append(tree.pop(0))
Run Code Online (Sandbox Code Playgroud)

如果您不喜欢"简单"参数,请查看collections.deque上面(链接)线程中提到的迭代器.