Python:检查生成器中是否存在对象

时间:2014-08-24 16:25:55

标签: python list range generator

我有一个错误是由于检查“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

在我检查是否存在某个对象(加快检查)之前,我通常会将生成器变成一个集合,这样可以解决问题,但我非常想知道这里发生了什么?

1 个答案:

答案 0 :(得分:6)

当您遍历生成器的元素时,使用它们。

试试这个:

len(list(first_hundred_primes)) > 0
=> True
len(list(first_hundred_primes)) > 0
=> False

即。你第一次使用in(迭代它们)或者列出所有元素(最多5个)时你已经完成了元素的使用,因此生成器在此之后不再生成5。在第二次之后,它不再生成任何东西。

您的选择:

  1. 在使用之前将您的生成器转换为列表(或集合):first_hundred_primes = list(first_hundred_primes)
  2. 每次创建一个新的生成器:5 in primes(100); 5 in primes(100); ...
  3. 使用itertools.tee
  4. 编辑:

    关于range的问题:range不是生成器。

    在python2中,它只返回一个列表。没问题。

    在python3中,它返回一个看起来像集合的特殊对象。它不必实际存储范围内的所有数字,它只是根据定义范围的规则实现列表操作。例如。 len已实施为stop-start。因为它代表一个集合而不是一个生成器,所以你可以多次迭代它,而不需要消耗#34;元素。