Tho*_*hor 8 python dictionary iterator
我目前正在研究python中的迭代.
我遇到了以下代码.
def myzip(*args):
iters = map(iter, args)
while iters:
res = [next(i) for i in iters]
print(res)
yield tuple(res)
list(myzip('abc', '1mnop'))
Run Code Online (Sandbox Code Playgroud)
当我在3.X中运行代码时,代码会进入无限循环并打印
['a', '1']
[]
[]
[]
...
Run Code Online (Sandbox Code Playgroud)
我从作者那里得到的解释是
3.X map返回一次性可迭代对象而不是2.X中的列表.在3.X中,只要我们在循环中运行一次列表理解,它就会耗尽,但仍然是真的(并且res将永远是[]).
但我仍在努力了解正在发生的事情及其发生的原因.
而且,为什么变量res仅('a', 'l')在while循环的第一次迭代中赋值?为什么没有分配('b', 'm'),然后('c', 'n')在第二次和第三次迭代?
Chr*_*ean 16
但我仍在努力了解正在发生的事情及其发生的原因.
而且,为什么变量
res仅('a', 'l')在while循环的第一次迭代中赋值? 之后res总是会分配一个空列表[].为什么没有分配('b', 'm'),然后('c', 'n')在第二次和第三次迭代?
您在Python 3中发布的代码在Python 3中失败的原因是因为内置函数在Python 3 中map返回迭代器,而不是像在Python 2中那样返回列表.
当然,除非你知道迭代器是什么,否则这并没有真正解释.虽然我可以深入了解迭代器究竟是什么1,但是理解迭代器的重要部分是:迭代器只能迭代一次.一旦你迭代了迭代器一次,就会筋疲力尽.完成.你不能再使用它了.2
当您iters在代码中的列表解析中迭代迭代器时,则iters完成并耗尽,并且不能再使用.所以基本上所有的列表理解:
[next(i) for i in iters]
Run Code Online (Sandbox Code Playgroud)
是从每个迭代器中获取第一个项目iters(哪些是'a'和'l'),然后将它们存储在列表中.在while循环的下一次迭代中,iters不能再使用它,它是空的.所以空列表被yield编辑.这就是为什么在第一列表yield编辑你看'a'和'l',而其他后续的列表是空的.
最后,你的代码降级为无限循环的原因是因为迭代器对象 - 即使是已经耗尽的对象 - 将True在布尔上下文中求值:
>>> it = map(str, [1, 2])
>>> next(it)
'1'
>>> next(it)
'2'
>>> # The `it` iterator is exhausted
>>> next(it)
Traceback (most recent call last):
File "<pyshell#17>", line 1, in <module>
next(it)
StopIteration
>>> bool(it) # but it still evaluates to `True` in a boolean context
True
>>>
Run Code Online (Sandbox Code Playgroud)
解决此问题的最简单方法是将返回的迭代器强制map转换为列表,因为list对象支持多次迭代:
>>> def custom_zip(*args):
iters = list(map(iter, args))
while iters:
yield tuple([next(it) for it in iters])
>>> list(custom_zip('abc', [1, 2, 3]))
[('a', 1), ('b', 2), ('c', 3)]
>>> list(custom_zip('def', [4, 5, 6]))
[('d', 4), ('e', 5), ('f', 6)]
>>> list(custom_zip([1, 2, 3], [1, 4, 9], [1, 8, 27]))
[(1, 1, 1), (2, 4, 8), (3, 9, 27)]
>>>
Run Code Online (Sandbox Code Playgroud)
正如@Chris_Rands所指出的那样,尽管上面的代码有效,但zip在Python 3+中实现自定义函数的更惯用的方法是:
def custom_zip(*args):
return map(lambda *x: x, *args)
Run Code Online (Sandbox Code Playgroud)
1 作为旁注,如果您想了解迭代器的深入内容,请参阅问题Python的迭代器,迭代和迭代协议究竟是什么?
2 要更全面地了解耗尽的迭代器为何进行评估True,请参阅问题如何在耗尽时将生成器/迭代器评估为False?