我有一个 bug,它是由检查“if x in generator”的变化结果引起的
def primes(upper_limit):
for n in range(2, upper_limit):
if all(n % i > 0 for i in range(2, n)):
yield n
first_hundred_primes = primes(100)
print(5 in first_hundred_primes)
print(5 in first_hundred_primes)
print(5 in first_hundred_primes)
print(5 in first_hundred_primes)
print(5 in first_hundred_primes)
这给出了输出:
True
False
False
False
False
我假设它不是为了检查生成器中是否存在对象,但如果是这种情况,为什么它不抛出一些错误,为什么它会起作用?
>>> hundred_generator = range(1,100)
>>> 50 in hundred_generator
True
>>> 50 in hundred_generator
True
>>> 50 in hundred_generator
True
我通常在检查生成器中是否存在某些对象(以加快检查速度)之前将生成器变成一个集合,这解决了问题,但我非常想知道这里发生了什么?
请您参考如下方法:
当您迭代生成器的元素时,您消耗它们。
试试这个:
len(list(first_hundred_primes)) > 0
=> True
len(list(first_hundred_primes)) > 0
=> False
即第一次使用 in(遍历它们)或 at 列出最多 5 个元素时,您已经完成了对元素的消耗,因此生成器不会在此之后再次生成 5。第二次后,它不再生成任何东西。
您的选择:
- 在使用之前将生成器转换为列表(或集合):
first_hundred_primes = list(first_hundred_primes) - 每次创建一个新的生成器:
5 in primes(100); 5 个素数 (100); ... - 使用
itertools.tee
编辑:
关于您关于 range 的问题:range 不是生成器。
在 python2 中,它只是返回一个列表。没问题。
在 python3 中,它返回一个看起来像集合的特殊对象。它不必实际存储范围内的所有数字,它只是根据定义范围的规则实现列表操作。例如。 len 实现为 stop-start。由于它代表一个集合,而不是一个生成器,您可以多次迭代它,而无需“消耗”元素。
