use*_*919 5 python list-comprehension
我试图弄清楚为什么我的嵌套列表理解不起作用。代码:
def myzip(*args):
try:
x = [iter(i) for i in [*args]]
while True:
# for i in range(5):
yield [next(ii) for ii in x]
# I want to know why the commented line below won't work
# yield [next(ii) for ii in [iter(i) for i in [*args]]]
# or why this outputs [1, 'a']
# return [next(ii) for ii in [iter(i) for i in [*args]]]
except:
pass
def main():
print(list(myzip([1, 2, 3, 4, 5], ['a', 'b', 'c'])))
if __name__ == '__main__':
main()
Run Code Online (Sandbox Code Playgroud)
如果我分配[iter(i) for i in [*args]]给x然后使用此列表理解,[next(ii) for ii in x]一切正常。输出将是:
[[1, 'a'], [2, 'b'], [3, 'c']]
Run Code Online (Sandbox Code Playgroud)
但是,如果我尝试省略变量x并在一个更大的列表理解(注释行)中执行[next(ii) for ii in [iter(i) for i in [*args]]]它,它将进入无限循环。如果将无限循环替换为 for 循环(注释行),则输出为:
[[1, 'a'], [1, 'a'], [1, 'a'], [1, 'a'], [1, 'a']]
Run Code Online (Sandbox Code Playgroud)
此外,如果我尝试return [next(ii) for ii in [iter(i) for i in [*args]]]它只会返回:
[1, 'a']
Run Code Online (Sandbox Code Playgroud)
有人能告诉我这是为什么吗?
所以我不会直接回答你的问题(因为评论很好地涵盖了这一点),但我将展示如何将其作为一个可怕的衬里来完成,只是为了好玩:
def my_zip(*args):
yield from iter(lambda data=[iter(a) for a in args]: [next(d) for d in data], None)
Run Code Online (Sandbox Code Playgroud)
共有三个部分。
iter, afteryield from会创建一个callable_iterator. 这将重复调用其第一个参数(the lambda),直到它看到第二个参数(在本例中为哨兵值None)或者遇到任何异常时StopIteration错误StopIterationlambdai 有一个默认值,data它是您想要迭代的迭代器的列表。this 创建一次,因此后续对该函数的每次调用都将引用 this。lambda手动推进每个迭代器一次。data这将一直持续到其中一个迭代器耗尽为止,此时 aStopIteration将被引发。iter调用一旦获得它就会立即退出,StopIterationlist消费者,这会导致它停止迭代。由于异常,哨兵值并不重要。最后:请永远不要在真正的代码中这样做。
编辑:一些示例输出
In [90]: list(my_zip('abcd', [1,2,3]))
Out[90]: [['a', 1], ['b', 2], ['c', 3]]
In [91]: list(my_zip('abcd', [1,2,3,4,5,6]))
Out[91]: [['a', 1], ['b', 2], ['c', 3], ['d', 4]]
Run Code Online (Sandbox Code Playgroud)
解释编辑:向@superb rain 致敬,感谢他们在下面的聪明评论。