即使在确认重新分配后,变量也会引用错误的迭代器

时间:2019-02-14 16:56:41

标签: python

我有以下循环重新分配给迭代器变量:

currentPrime = None
sieve = iter(range(2, 10))
while True:
    try:
        # The first value should be prime.
        currentPrime = next(sieve)
    except StopIteration:
        # Stop when sieve is empty.
        print(currentPrime)
        break
    print(currentPrime)
    # Filter out all multiples of currentPrime.
    sieve = (x for x in sieve if x % currentPrime)
    #print(tuple(sieve))

即使我在循环的每次迭代中都应用了过滤器,输出也会遍历整个范围:

2
3
4
5
6
7
8
9
9

如果我取消对最后一个print调用的注释,则会看到(3, 5, 7, 9),这意味着sieve的过滤器和赋值工作正常,但是next(sieve)调用以某种方式访问​​了原始没有变量指向的迭代器。

你知道这里发生了什么吗?我正在使用Python 3.7.0。

2 个答案:

答案 0 :(得分:1)

正如user2357112所说,“ {currentPrime是在使用时查找的,而不是在生成器时查找的。”

一种解决方案是将filter与一个lambda一起使用,以对currentPrime的当前值进行本地化。请注意lambda如何使用默认参数创建本地变量:

currentPrime = None
sieve = iter(range(2, 10))
while True:
    try:
        # The first value should be prime.
        currentPrime = next(sieve)
    except StopIteration:
        # Stop when sieve is empty.
        print(currentPrime)
        break
    # Filter out all multiples of currentPrime.
    sieve = filter(lambda x, prime=currentPrime: x % prime, sieve)

答案 1 :(得分:0)

如果我没记错的话,有一堆发电机。

会发生什么(TL; DR:所有生成器都引用一个currentPrime实例,然后引用惰性):

  1. 从范围迭代器获取值2。

  2. 创建生成器表达式(A)。变量currentPrime = 2现在是 NOT 免费的(不是关闭的)。生成器消耗其余范围(3..9)。

  3. 从生成器A获取值3(3%2为True)

  4. 创建生成器表达式(B)。 两个发生器(A,B)的变量currentPrime = 3。发电机消耗发电机A的其余部分(4..9)。

  5. 从生成器B获取值4。请参见:next()→B.next(A)→A产生4(A检查:4% 3 为True),然后B检查4%3是正确的。

  6. 创建生成器表达式(C)...,依此类推。

生成器中的变量未关闭,请参见:

>>> a = 5
>>> gen = (a for i in range(3))
>>> a = 3
>>> list(gen)
[3, 3, 3]