对同一个iterable使用多个迭代器(使用枚举),发生了什么?

2024-09-28 23:31:56 发布

您现在位置:Python中文网/ 问答频道 /正文

考虑下面的例子:

s = 'abc'
[(c1, c2) for j, c2 in enumerate(s) for i, c1 in enumerate(s)]

输出:

[('a', 'a'),
 ('b', 'a'),
 ('c', 'a'),
 ('a', 'b'),
 ('b', 'b'),
 ('c', 'b'),
 ('a', 'c'),
 ('b', 'c'),
 ('c', 'c')]

如果在列表理解之外调用enumerate,并且将迭代器分配给变量,我希望得到相同的输出:

it1, it2 = enumerate(s), enumerate(s)
[(c1, c2) for j, c2 in it1 for i, c1 in it2]

但我得到:

[('a', 'a'), ('b', 'a'), ('c', 'a')]

发生了什么事?我使用Python 3.6.9


Tags: in列表for例子abcc2c1enumerate
3条回答

发生的情况是,内部迭代器在外部迭代器的第一次迭代后耗尽:

s = 'abc'
it1 = enumerate(s)
it2 = enumerate(s)

for i, x in it1:
    for j, y in it2:  # <  gets consumed when i = 0 and stays empty
        ...

相比之下:

s = 'abc'

for i, x in enumerate(s):
    for j, y in enumerate(s):  # <  gets recreated at each iteration
        ....

如果需要持久性,请将其括在listtuple中:

itr = list(enumerate(s))
print([(c1, c2) for j, c2 in itr for i, c1 in itr])
# [('a', 'a'), ('b', 'a'), ('c', 'a'), ('a', 'b'), ('b', 'b'), ('c', 'b'), ('a', 'c'), ('b', 'c'), ('c', 'c')]

尽管如此,请注意多次使用enumerate()与将其封装在listtuple中的内存占用情况不同

enumerate内置函数返回一个iterator,一旦元素耗尽,它就会停止

在第一个版本中,您正在为第一个循环的每个迭代构建一个新的enumerate(s),在第二个循环中,您正在使用它

在第二个版本中,it2已经完成了第一个循环的第一次迭代中的元素

s = 'abc'

def my_enumerate(s, name):
    print('a new enumerate: ', name)
    for i in enumerate(s):
        yield i
    print(f'the enumerate {name} is exhausted ')

[(c1, c2) for j, c2 in my_enumerate(s, 'it1') for i, c1 in my_enumerate(s, 'it2')]

输出:

a new enumerate:  it1
a new enumerate:  it2
the enumerate it2 is exhausted 
a new enumerate:  it2
the enumerate it2 is exhausted 
a new enumerate:  it2
the enumerate it2 is exhausted 
the enumerate it1 is exhausted 
[('a', 'a'),
 ('b', 'a'),
 ('c', 'a'),
 ('a', 'b'),
 ('b', 'b'),
 ('c', 'b'),
 ('a', 'c'),
 ('b', 'c'),
 ('c', 'c')]

以及:

it1, it2 = my_enumerate(s, 'it1'), my_enumerate(s, 'it2')
[(c1, c2) for j, c2 in it1 for i, c1 in it2]

输出:

a new enumerate:  it1
a new enumerate:  it2
the enumerate it2 is exhausted 
the enumerate it1 is exhausted 
[('a', 'a'), ('b', 'a'), ('c', 'a')]

区别在于:

s = 'abc'
[(c1, c2) for j, c2 in enumerate(s) for i, c1 in enumerate(s)]

为第一个for上生成的每个值创建一个新的c1枚举数。在第二个示例中,使用了相同的枚举数(it2)——当第一个for进入下一个迭代(c2=“b”)并尝试迭代“it2”时,它会在到达“c”时被检查——并且整个表达式结束

相关问题 更多 >