可循环使用的循环法

时间:2016-03-02 12:09:34

标签: python-3.x

考虑以下简单的循环实现:

from itertools import chain, repeat

class RoundRobin:
    def __init__(self, iterable):
        self._iterable = set(iterable)

    def __iter__(self):
        for value in chain.from_iterable(repeat(self._iterable)):
            yield value

使用示例:

machines = ['test1', 'test2', 
            'test3', 'test4']
rr_machines = RoundRobin(machines)
for machine in rr_machines:
   # Do something
   pass

虽然这有效,但我想知道是否有办法修改RoundRobin类中的迭代,这也会影响现有的迭代器。

E.g。假设当我从迭代器中消耗值时,集合中的一台机器变得不可用,我想阻止它被返回。

我能想到的唯一解决方案是实现一个单独的Iterator类。当然,当所有机器都变得不可用并且不能返回更多值时(StopIteration异常?),仍然存在问题该怎么办。

1 个答案:

答案 0 :(得分:1)

Itertools'repeat制作底层迭代器的副本,在本例中,是包含元素的set

这是创建repeat的另一个实现的一个主题,它将在整个集合的每次迭代中重新创建这样的副本。这是可能的,因为在这种情况下,我们知道要重复的迭代器是一个容器,而itertools.repeat必须使用任何迭代器(所以,记住第一次迭代的值):

def mutable_repeat(container):
    while True:
        for item in container.copy():
            yield item

只需使用此代替重复,您就可以对self._iterable集进行“即时”更改,并且可以在该集合中添加/删除新值。 (虽然删除的值最有可能在删除之前最后一次发布)

如果您需要防止发出删除的值一次,您可以通过添加更多逻辑来轻松防范它 - 而不是直接从课外与self._iterable进行迭代,你可以这样做:

class RoundRobin:
    def __init__(self, iterable):
        self._iterable = set(iterable)
        self._removed = set()

    def __iter__(self):
        for value in chain.from_iterable(self.repeat()):
            yield value

    def remove(self, item):
        self._removed.add(item)
        self._iterable.remove(item)

    def add(self, item):
        self._iterable.add(item)

    def repeat(self):
        while True:
            for item in self._iterable.copy():
                if not item in self._removed:
                    yield item
            self._removed = set()