gbr*_*ios 10 python list-comprehension list generator
我发现这种理解非常适用于展平列表列表:
>>> list_of_lists = [(1,2,3),(2,3,4),(3,4,5)]
>>> [item for sublist in list_of_lists for item in sublist]
[1, 2, 3, 2, 3, 4, 3, 4, 5]
Run Code Online (Sandbox Code Playgroud)
我喜欢这比使用更好itertools.chain(),但我无法理解它.我试过用括号括起来的部分,看看我是否可以减少复杂性,但现在我只是更加困惑:
>>> [(item for sublist in list_of_lists) for item in sublist]
[<generator object <genexpr> at 0x7ff919fdfd20>, <generator object <genexpr> at 0x7ff919fdfd70>, <generator object <genexpr> at 0x7ff919fdfdc0>]
>>> [item for sublist in (list_of_lists for item in sublist)]
[5, 5, 5]
Run Code Online (Sandbox Code Playgroud)
我觉得我很难理解,因为我不太明白发电机是如何工作的......我的意思是,我以为我做了,但现在我真的很怀疑.就像我说的,我喜欢这个成语是多么紧凑,这正是我需要的,但我不愿意使用我不理解的代码.
谁能解释一下究竟发生了什么?
the*_*eye 11
当我第一次开始列表理解时,我读到的就像英语句子一样,我能够很容易地理解它们.例如,
[item for sublist in list_of_lists for item in sublist]
Run Code Online (Sandbox Code Playgroud)
可以像
for each sublist in list_of_lists and for each item in sublist add item
Run Code Online (Sandbox Code Playgroud)
此外,过滤部分可以读作
for each sublist in list_of_lists and for each item in sublist add item only if it is valid
Run Code Online (Sandbox Code Playgroud)
而相应的理解将是
[item for sublist in list_of_lists for item in sublist if valid(item)]
Run Code Online (Sandbox Code Playgroud)
它们就像地雷一样,只有在使用next协议调用时才会触发.它们类似于函数,但是直到引发异常或函数结束,它们才会耗尽,并且可以一次又一次地调用它们.重要的是,它们保留了先前调用和当前调用之间的状态.
生成器和函数之间的区别在于,生成器使用yield关键字将值赋给调用者.在生成器表达式的情况下,它们类似于列表推导,第一个表达式是实际值"被屈服".
有了这个基本的理解,如果我们看一下你在问题中的表达方式,
[(item for sublist in list_of_lists) for item in sublist]
Run Code Online (Sandbox Code Playgroud)
您正在将列表理解与生成器表达式混合使用.这将是这样的
for each item in sublist add a generator expression which is defined as, for every sublist in list_of_lists yield item
Run Code Online (Sandbox Code Playgroud)
这不是你心中的想法.并且由于不迭代生成器表达式,因此生成器表达式对象将按原样添加到列表中.由于在没有使用下一个协议调用的情况下不会对它们进行评估,因此它们不会产生任何错误(如果有的话,除非它们有语法错误).在这种情况下,它将产生运行时错误,因为sublist尚未定义.
另外,在最后一种情况下,
[item for sublist in (list_of_lists for item in sublist)]
Run Code Online (Sandbox Code Playgroud)
for each sublist in the generator expression, add item and the generator expression is defined as for each item in sublist yield list_of_lists.
Run Code Online (Sandbox Code Playgroud)
for循环将迭代任何可迭代的下一个协议.因此,将评估生成器表达式,并且item将始终是迭代中的最后一个元素,sublist并且您将在列表中添加它.这也会产生运行时错误,因为尚未定义子列表.
Mar*_*ers 10
从左到右阅读for循环,就好像它们是嵌套的一样.左边的表达式是在最终列表中生成每个值的表达式:
for sublist in list_of_lists:
for item in sublist:
item # added to the list
Run Code Online (Sandbox Code Playgroud)
列表推导还支持if测试以过滤使用的元素; 这些也可以看作嵌套语句,与for循环相同.
通过添加括号,您更改了表达式; 括号中的所有内容现在都是要添加的左侧表达式:
for item in sublist:
(item for sublist in list_of_lists) # added to the list
Run Code Online (Sandbox Code Playgroud)
for像这样的循环是生成器表达式.它的工作方式与列表理解完全相同,只是它不构建列表.而是根据需要生成元素.您可以向生成器表达式询问下一个值,然后是下一个值,等等.
在这种情况下,必须有一个预先存在的sublist对象才能使其工作; list_of_lists毕竟,外环已经不再结束了.
您的最后一次尝试转换为:
for sublist in (list_of_lists for item in sublist):
item # aded to the list
Run Code Online (Sandbox Code Playgroud)
这list_of_lists是循环的生成器表达式中的循环元素for item in sublist.同样,sublist必须已经存在才能使其发挥作用.然后循环将预先存在的内容添加item到最终列表输出中.
在你的情况下,显然sublist是一个包含3个项目的列表; 你的最终名单产生了3个元素.item是必然的5,所以你5输出3次.