周期如何阻止发电机抛出停止异常



考虑此示例:

from itertools import cycle
def foo():
    for i in range(3):
        yield i
c = cycle(foo())
next(c)  # -> 0
next(c)  # -> 1
next(c)  # -> 2 [StopIteration should be thrown here normally]
next(c)  # -> 0
...

cycle如何通过StopIteration阻止发电机令人兴奋?我认为生成器只能执行一次,因为发电机只返回其当前值并移动。

cycle是否只是在抛出StopIteration时重新创建发电机?当我迭代例如大型Numpy阵列时,这会成为一个问题(效率低下(吗?

次要问题:这是用迭代器/发电机循环大型数据集的" Pythonic"方式?或者我应该将循环逻辑直接传输到发电机本身(例如定义索引并使用重置索引使用while循环(?

我的目的是有效地循环浏览大型数据集(主要是numpy阵列;> 100.000个条目(。

cycle如何阻止发电机通过StopIteration兴奋?

不是。发电机到达其末端,并以StopIteration的正常方式退出。cycle存储发电机的输出,当cycle看到StopIteration时,它将切换到生成生成器的存储历史记录中的项目。

user2357112已回答了您的第一个Quesiton。

至于您的第二个,对于像numpy数组这样的容器,我们可以创建相当于循环的循环,而无需在内存中进行额外的副本。请注意,这与发电机不起作用!如果我们要一遍又一遍地使用它们,或者至少有一种方法可以按需生成它们。

def cycle(container):
    if iter(container) is container:
        raise TypeError('need a container, not a generator')
    while True:
       yield from container

# this works correctly for a container
for i, char in enumerate(cycle('abc')):
    print(char)
    if i > 10:
        break

假设我们想从文件中重复阅读而不创建内存中每行的副本。

我们可以创建一个实现__iter__的"包装类别",然后将我们的新cycle方法与之使用。

class Reader():
    def __init__(self, path, *args, **kwargs):
        self.path, self.args, self.kwargs = path, args, kwargs
    def __iter__(self):
        with open(self.path, *self.args, **self.kwargs) as file:
            yield from file
 #eg:
 for line in cycle(Reader(filepath)):
     #somecode