简体   繁体   English

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

[英]python iterable list comprehension in list comprehension

I'm trying to figure out why my nested list comprehension doesn't work.我试图弄清楚为什么我的嵌套列表理解不起作用。 Code:代码:

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

if I assign [iter(i) for i in [*args]] to x and then use this list comprehension [next(ii) for ii in x] everything works ok.如果我将[iter(i) for i in [*args]]分配给x ,然后使用此列表理解[next(ii) for ii in x]一切正常。 and the output will be: output 将是:

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

But if I try to ommit variable x and do it in one bigger list comprehension (commented line) [next(ii) for ii in [iter(i) for i in [*args]]] it goes in infinite loop.但是,如果我尝试省略变量x并在一个更大的列表理解(注释行) [next(ii) for ii in [iter(i) for i in [*args]]]中执行它,它将进入无限循环。 If you replace infinite loop with the for loop (commented line), the output is:如果将无限循环替换为 for 循环(注释行),则 output 为:

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

Moreover, if I try return [next(ii) for ii in [iter(i) for i in [*args]]] it just returns:此外,如果我尝试return [next(ii) for ii in [iter(i) for i in [*args]]]它只会返回:

[1, 'a']

Can someone tell me why is that?有人能告诉我这是为什么吗?

so i'm not going to answer your question directly (as the comments pretty well have this covered), but i am going to show how this can be done as a horrible one liner, just for fun:所以我不打算直接回答你的问题(因为评论很好地涵盖了这一点),但我将展示如何将其作为一个可怕的单线来完成,只是为了好玩:

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

there are three parts.有三个部分。

  • the first usage of iter , after yield from , creates a callable_iterator . iter的第一次使用,在yield from之后,创建了一个callable_iterator this will repeat calling its first argument (the lambda ) until it either sees its second argument (the sentinel value, in this case None ) OR it gets a StopIteration error it encounters any exception.这将重复调用它的第一个参数( lambda ),直到它看到它的第二个参数(哨兵值,在这种情况下为None )或者它遇到任何异常时遇到StopIteration错误 (in this case, it will be a StopIteration exception. (在这种情况下,它将是一个StopIteration异常。
  • in the lambda i have a default value for data which is a list of the iterators you want to iterate over.lambda中,我有一个data的默认值,它是您要迭代的迭代器的列表。 this gets created once, so each subsequent call to the function will reference this.这被创建一次,因此对 function 的每个后续调用都将引用它。
  • finally, in the body of the lambda , i manually advance each of the iterators in data one time per function call.最后,在lambda的主体中,我在每个 function 调用中手动将data中的每个迭代器推进一次。 this will continue until one of the iterators is exhausted, at which point a StopIteration will be raised.这将一直持续到其中一个迭代器用尽,此时将引发StopIteration as you can see, in this case, the sentinel value doesn't matter because the first iter call will bail as soon as it gets its StopIteration this will be bubbled up to the list consumer which causes it to, well, stop iterating .如您所见,在这种情况下,哨兵值无关紧要,因为第一个iter调用将在它获得StopIteration后立即退出,这将冒泡到list使用者,这会导致它停止迭代 because of the exception, the sentinel value doesn't matter.由于异常,哨兵值无关紧要。

finally: please never actually do this in real code.最后:请永远不要在实际代码中实际执行此操作。


edit: some sample output编辑:一些样品 output

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]]

explanation edits: hat tip to @superb rain for their smart comments below.解释编辑:向@superb rain 致敬,感谢他们在下面的聪明评论。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM