列表理解
当我第一次开始使用列表理解时,我像阅读英语句子一样阅读它,并且能够轻松理解它们。例如,
[item for sublist in list_of_lists for item in sublist]
可以读成
for each sublist in list_of_lists and for each item in sublist add item
另外,过滤部分可以理解为
for each sublist in list_of_lists and for each item in sublist add item only if it is valid
相应的理解是
[item for sublist in list_of_lists for item in sublist if valid(item)]
发电机
它们就像地雷,只有在用next
协议。它们与函数类似,但是直到引发异常或到达函数末尾为止,它们都不会耗尽,并且可以一次又一次地调用。重要的是,它们保留了上一次调用和当前调用之间的状态。
生成器和函数之间的区别在于,生成器使用yield
关键字将值返回给调用者。对于生成器表达式,它们类似于列表理解,第一个表达式是“生成”的实际值。
有了这个基本的理解,如果我们看看你在问题中的表达,
[(item for sublist in list_of_lists) for item in sublist]
您将列表理解与生成器表达式混合在一起。这将被读成这样
for each item in sublist add a generator expression which is defined as, for every sublist in list_of_lists yield item
这不是你的想法。并且由于生成器表达式没有被迭代,因此生成器表达式对象将按原样添加到列表中。由于它们不会在没有被下一个协议调用的情况下被评估,因此它们不会产生任何错误(如果有的话,除非它们有语法错误)。在这种情况下,它将产生运行时错误,如下所示sublist
尚未定义。
另外,在最后一种情况下,
[item for sublist in (list_of_lists for item in sublist)]
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.
for 循环将使用下一个协议迭代任何可迭代对象。因此,生成器表达式将被求值并且item
将始终是迭代中的最后一个元素sublist
并且您正在将其添加到列表中。这也会产生运行时错误,因为子列表尚未定义。