python 是否在生成器对象上使用实习? (i for i in range(n)) 的奇怪行为

Does python use interning on generator objects? Weird behaviour with (i for i in range(n))

为什么这两个循环给出的结果不同? (是的,我知道第二个版本的风格很糟糕。但我仍然希望它能提供相同的输出。)

gen1 = range(3)
gen2 = range(3)
print("First attempt")
for i in gen1:
  for j in gen2:
    print(i,j)

gen1 = (i for i in range(3))
gen2 = (i for i in range(3))
print("Second attempt")
for i in gen1:
  for j in gen2:
    print(i,j)

使用 Python 3.6.9 输出(我用 Python 2.7.15 得到相同的结果):

First attempt
(0, 0)
(0, 1)
(0, 2)
(1, 0)
(1, 1)
(1, 2)
(2, 0)
(2, 1)
(2, 2)
Second attempt
(0, 0)
(0, 1)
(0, 2)

range是它自己的类型。它是可迭代的,但不是 迭代器(或生成器)——您可以多次迭代它,每次创建独立的迭代器:

>>> r = range(2)
>>> list(r)
[0, 1]
>>> list(r)
[0, 1]
>>> next(r)
TypeError: 'range' object is not an iterator

生成器,与生成器表达式一样, 迭代器。当你迭代它们时,你推进了它们。

>>> r = (1 + x for x in range(2))
>>> list(r)
[1, 2]
>>> list(r)
[]
>>> r = (1 + x for x in range(2))
>>> iter(r) is r
True
>>> next(r)
1

而且,明确回答第一个问题,此行为与实习无关。在 for i in gen1 循环的第一次迭代期间,消耗了 gen2,因此剩余的迭代什么都不做。