列表理解中的python可迭代列表理解

问题描述

我试图弄清楚为什么嵌套列表理解无法正常工作。代码

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()

如果我将[iter(i) for i in [*args]]分配给x,然后使用此列表理解[next(ii) for ii in x],一切正常。输出为:

[[1,'a'],[2,'b'],[3,'c']]

但是,如果我尝试忽略变量x,并在一个更大的列表理解(注释行)[next(ii) for ii in [iter(i) for i in [*args]]]中进行操作,它将陷入无限循环。如果将无限循环替换为for循环(带注释的行),则输出为:

[[1,[1,'a']]

此外,如果我尝试return [next(ii) for ii in [iter(i) for i in [*args]]],它只会返回:

[1,'a']

有人可以告诉我为什么吗?

解决方法

所以我不会直接回答您的问题(因为评论已经很好地涵盖了这个问题),但是我将展示如何将它作为可怕的衬纸来完成好玩:

def my_zip(*args):
    yield from iter(lambda data=[iter(a) for a in args]: [next(d) for d in data],None)

共有三个部分。

  • iter之后,yield from的首次使用将创建callable_iterator。这将重复调用其第一个参数(lambda),直到它看到其第二个参数(哨兵值,在这种情况下为None),或者它得到StopIteration错误遇到 any 异常。 (在这种情况下,将是StopIteration例外。
  • lambda中,我有一个data的默认值,它是您要迭代的迭代器的列表。该函数仅创建一次,因此以后每次对该函数的调用都将引用此函数。
  • 最后,在lambda的主体中,我每个函数调用手动在data中推进每个迭代器一次。这将一直持续到迭代器之一用尽为止,此时将引发StopIteration。如您所见,在这种情况下,哨兵值并不重要,因为第一个iter调用一旦获得StopIteration就会保释,这会冒泡list消费者,导致它停止迭代。由于存在异常,因此哨兵值无关紧要。

最后:请永远不要真正用真实的代码来做。


编辑:一些示例输出

In [90]: list(my_zip('abcd',[1,2,3]))
Out[90]: [['a',1],['b',2],['c',3]]

In [91]: list(my_zip('abcd',3,4,5,6]))
Out[91]: [['a',3],['d',4]]

说明编辑:在下面向他们推荐@superb Rain的聪明话。