在python2.7中,我试图将字符串列表中的每个项目添加到另一个项目中(例如,在列表['b','c']中的每个项目之前添加项目'a')。从How to add list of lists in a list comprehension开始,我确定了正确的命令,归结为:
>>> [i for x in ['b', 'c'] for i in ['a', x]]
['a', 'b', 'a', 'c']
纯粹基于临时i和x变量,下面的版本似乎更具可读性。但是,它给出了完全不同的结果。为什么这不会给出相同的结果?
>>> [i for i in ['a', x] for x in ['b', 'c']]
['a', 'a', 'c', 'c']
更加好奇的是,'b'条目发生了什么?
答案 0 :(得分:9)
列表推导中的\
循环始终以嵌套顺序列出。您可以使用相同的嵌套顺序将两种理解都写成常规循环;请记住,只有第一个for
之前的表达式产生最终值,所以将它放在循环中。
所以for
变为:
[i for x in ['b', 'c'] for i in ['a', x]]
和for x in ['b', 'c']:
for i in ['a', x]:
i # added to the final list
变为:
[i for i in ['a', x] for x in ['b', 'c']]
正如您所看到的,如果没有先在列表解析之外定义for i in ['a', x]:
for x in ['b', 'c']:
i
,第二个版本将无法运行,因为否则x
列表不能创建。另请注意,内部循环['a', x]
的{{1}}否则将被忽略。所有你得到的是x
重复。在内循环中该值列表中的值并不重要,只有循环的长度才重要。
在您的情况下,您的输出将通过首先设置for x in ['b', 'c']
来解释;然后你获得外部循环的i
,内循环迭代两次,因此x = 'c'
被添加两次,然后设置for i in ['a', 'c']
,你得到'a'
两次。
实际上,在Python 2中,变量使用列表理解和泄漏,就像常规i = 'c'
循环泄漏中使用的变量一样;使用'c'
后,for
仍然可用并绑定到for x in ['b', 'c']: pass
。这是x
来自的地方:
'c'
x = 'c'
和>>> [i for x in ['b', 'c'] for i in ['a', x]]
['a', 'b', 'a', 'c']
>>> i
'c'
>>> x
'c'
>>> [i for i in ['a', x] for x in ['b', 'c']]
['a', 'a', 'c', 'c']
反映了他们最后绑定的内容,因此运行下一个列表解析会在第一个(外部)循环迭代i
时起作用
从全局变量中删除x
,第二个列表理解无法运行:
['a', 'c']
上述完整的常规x
循环版本也是如此:
>>> del x
>>> [i for i in ['a', x] for x in ['b', 'c']]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
在Python 3中,列表推导在新范围内执行(就像生成器表达式,dict理解和集合理解已经在Python 2中执行)。