斐波那契生成器迭代器和无限生成器

问题描述

我有这个 FibIter 发生器。我正在尝试使用生成器表达式创建第二个。

def FibIter():
    yield 0
    yield 1
    x = 0
    y = 1
    while True:
        result = x + y
        x,y = y,result
        yield result

fibiter = FibIter()
fibiter_in_range = (x for i,x in enumerate(fibiter) if 100000 < i <= 100020)

现在,如果我在下面运行代码,什么都不会发生。

print(list(fibiter_in_range))

如果我运行下面的代码,数字会被打印出来,但 for 循环不会结束。

for x in fibiter_in_range:
    print(x)

我想我可以遍历 fibiter_in_range 直到使用完所有元素。

我对生成器有什么不了解?如何优雅地创建带有 n 范围为 100000-100020 的斐波那契数的迭代器?

解决方法

问题是您的生成器永远不会结束,即使在 i 达到其上限之后,您的生成器表达式也会不断从中获取输出。

做你想做的一个简单的方法是使用itertools.islice

from itertools import islice

def FibIter():
    yield 0
    yield 1
    x = 0
    y = 1
    while True:
        result = x + y
        x,y = y,result
        yield result

fibiter = FibIter()
fibiter_in_range = islice(fibiter,10,15)
print(list(fibiter_in_range))
# [55,89,144,233,377]
,

Python 不够聪明,无法知道 if 100000 < i <= 100020 会导致新生成器在 100020 后停止生成。据它所知,后面可能会有一些元素满足条件,所以需要不断拉取,看最终是否满足。

您可以使用 dropwhiletakewhile 进行过滤:

from itertools import takewhile,dropwhile

...


fibiter = FibIter()
fibiter_in_range = takewhile(lambda n: n <= 10002000,dropwhile(lambda n: n < 100000,fibiter))

>>> list(fibiter_in_range)
[121393,196418,317811,514229,832040,1346269,2178309,3524578,5702887,9227465]

不过,这基于数字的值进行过滤,而不是它们在生成器中的索引,因为您写道,您想“优雅地创建带有 n 范围为 100000-100020 的斐波那契数的迭代器?”。为了示例,我增加了上限,因为否则它找不到任何元素。