列表理解中for语句的顺序 [英] Order of for statements in a list comprehension

查看:84
本文介绍了列表理解中for语句的顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在python2.7中,我试图在字符串列表中的每个项目之前加上另一个项目(例如,在列表['b','c']中的每个项目之前添加项目'a').通过如何在列表理解中添加列表列表,我确定了正确的命令,其归结为:

In python2.7, I am trying to prepend every item in a list of strings with another item (eg. add item 'a' before every item in the list ['b', 'c']). From How to add list of lists in a list comprehension, I have determined the correct command, which boils down to:

>>> [i for x in ['b', 'c'] for i in ['a', x]]
['a', 'b', 'a', 'c']

纯粹基于临时i和x变量,以下版本似乎更具可读性.但是,它给出了完全不同的结果.为什么这不会给出相同的结果?

Based purely on the temporary i and x variables, the version below seems more readable. However, it gives a completely different result. Why does this not give the same result?

>>> [i for i in ['a', x] for x in ['b', 'c']]
['a', 'a', 'c', 'c']

更奇怪的是,"b"条目发生了什么?

Even more curious, what happened to the 'b' entry?

推荐答案

列表理解中的for循环始终按嵌套顺序列出.您可以使用相同的嵌套顺序将这两个理解写成常规循环.请记住,只有第一个for之前的表达式会产生最终值,因此请将其放入循环中.

The for loops in list comprehensions are always listed in nesting order. You can write out both of your comprehensions as regular loops using the same order to nest; remember that only the expression before the first for produces the final values, so put that inside the loops.

所以[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]列表.还要注意,内循环for x in ['b', 'c']x会被忽略.您得到的只是重复i.内循环中该列表中的值是什么都没关系,仅循环的长度不再重要.

As you can see, the second version would not be able to run without first defining x outside of your list comprehension, because otherwise the ['a', x] list could not be created. Also note that the x for the inner loop for x in ['b', 'c'] is otherwise ignored. All you get is i repeated. It doesn't matter what the values are in that list in the inner loop, only the length of the loop matters anymore.

在您的情况下,将首先设置x = 'c'来解释您的输出;那么对于外循环,您得到for i in ['a', 'c'],对内循环进行两次迭代,因此将'a'添加了两次,然后设置了i = 'c'并两次将'c'添加了.

In your case, your output would be explained by setting x = 'c' first; then you get for i in ['a', 'c'] for the outer loop, the inner loop iterates twice so 'a' is added twice, then i = 'c' is set and you get 'c' added twice.

碰巧,在Python 2中,列表理解'leak'中使用的变量,就像常规for循环泄漏中使用的变量一样;使用for x in ['b', 'c']: pass后,x将保持可用并绑定到'c'.这是您的x = 'c'来源:

As it happens, in Python 2, the variables using in a list comprehension 'leak', just like the variables used in a regular for loop leak; after using for x in ['b', 'c']: pass, x would remain available and bound to 'c'. This is where your x = 'c' comes from:

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

ix反映了它们最后绑定到的内容,因此运行下一个列表理解是在第一个( outer )循环遍历['a', 'c']时工作的.

i and x reflect what they were last bound to, so running the next list comprehension works as the first (outer) loop iterates over ['a', 'c'].

从全局变量中删除x,并且第二个列表理解完全无法运行:

Remove x from your globals and the second list comprehension simply fails to run:

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

上述完整的常规for循环版本也是如此:

The same happens to the full regular for loop versions above:

>>> for i in ['a', x]:
...     for x in ['b', 'c']:
...         i
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> x = 'foo'
>>> for i in ['a', x]:
...     for x in ['b', 'c']:
...         i
... 
'a'
'a'
'foo'
'foo'

在Python 3中,列表推导是在新作用域中执行的(就像生成器表达式,dict推导和set推导已经在Python 2中一样).

In Python 3, list comprehensions are executed in a new scope (just like generator expressions, dict comprehensions and set comprehensions already do in Python 2).

这篇关于列表理解中for语句的顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆