"列表理解"是什么意思?它是如何工作的,我该如何使用它?

Kev*_*uan 46 python list-comprehension list

我有以下代码:

[x ** 2 for x in range(10)]
Run Code Online (Sandbox Code Playgroud)

当我在Python Shell中运行它时,它返回:

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Run Code Online (Sandbox Code Playgroud)

我搜索过,似乎这被称为列表理解,但它是如何工作的?

Kev*_*uan 84

文档:

列表推导提供了创建列表的简明方法.常见的应用是创建新的列表,其中每个元素是应用于另一个序列的每个成员或可迭代的一些操作的结果,或者创建满足特定条件的那些元素的子序列.


关于你的问题,列表推导与下面的"普通"Python代码做同样的事情:

>>> l = [] 
>>> for x in range(10):
...     l.append(x**2)
>>> l
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Run Code Online (Sandbox Code Playgroud)

你怎么用一行写的?嗯......我们可以......可能......使用map()lambda:

>>> list(map(lambda x: x**2, range(10)))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Run Code Online (Sandbox Code Playgroud)

但是使用列表理解不是更清晰,更简单吗?

>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Run Code Online (Sandbox Code Playgroud)

基本上,我们可以做任何事情x.不仅如此x**2.例如,运行以下方法x:

>>> [x.strip() for x in ('foo\n', 'bar\n', 'baz\n')]
['foo', 'bar', 'baz']
Run Code Online (Sandbox Code Playgroud)

或者x用作另一个函数的参数:

>>> [int(x) for x in ('1', '2', '3')]
[1, 2, 3]
Run Code Online (Sandbox Code Playgroud)

例如,我们也可以x用作dict对象的关键字.让我们来看看:

>>> d = {'foo': '10', 'bar': '20', 'baz': '30'}
>>> [d[x] for x in ['foo', 'baz']]
['10', '30']
Run Code Online (Sandbox Code Playgroud)

组合怎么样?

>>> d = {'foo': '10', 'bar': '20', 'baz': '30'}
>>> [int(d[x].rstrip('0')) for x in ['foo', 'baz']]
[1, 3]
Run Code Online (Sandbox Code Playgroud)

等等.


您也可以使用ifif...else在列表中理解.例如,您只需要奇数range(10).你可以做:

>>> l = []
>>> for x in range(10):
...     if x%2:
...         l.append(x)
>>> l
[1, 3, 5, 7, 9]
Run Code Online (Sandbox Code Playgroud)

啊那太复杂了.以下版本怎么样?

>>> [x for x in range(10) if x%2]
[1, 3, 5, 7, 9]
Run Code Online (Sandbox Code Playgroud)

要使用if...else三元表达式,您需要放置if ... else ...x,而不是之后range(10):

>>> [i if i%2 != 0 else None for i in range(10)]
[None, 1, None, 3, None, 5, None, 7, None, 9]
Run Code Online (Sandbox Code Playgroud)

你听说过嵌套列表理解吗?您可以将两个或更多个fors放在一个列表中.例如:

>>> [i for x in [[1, 2, 3], [4, 5, 6]] for i in x]
[1, 2, 3, 4, 5, 6]

>>> [j for x in [[[1, 2], [3]], [[4, 5], [6]]] for i in x for j in i]
[1, 2, 3, 4, 5, 6]
Run Code Online (Sandbox Code Playgroud)

让我们谈谈第一部分,for x in [[1, 2, 3], [4, 5, 6]]它给出[1, 2, 3][4, 5, 6].然后,for i in x1,2,34,5,6.

警告:你总是需要把for x in [[1, 2, 3], [4, 5, 6]] 之前 for i in x:

>>> [j for j in x for x in [[1, 2, 3], [4, 5, 6]]]
Traceback (most recent call last):
  File "<input>", line 1, in <module>
NameError: name 'x' is not defined
Run Code Online (Sandbox Code Playgroud)

我们还设置了理解,字典理解生成器表达.

set comprehensions和list comprehensions基本相同,但前者返回一个集合而不是列表:

>>> {x for x in [1, 1, 2, 3, 3, 1]}
{1, 2, 3}
Run Code Online (Sandbox Code Playgroud)

它与以下相同:

>>> set([i for i in [1, 1, 2, 3, 3, 1]])
{1, 2, 3}
Run Code Online (Sandbox Code Playgroud)

一个字典理解 看起来像一套理解,但它使用{key: value for key, value in ...}{i: i for i in ...}代替 {i for i in ...}.

例如:

>>> {i: i**2 for i in range(5)}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
Run Code Online (Sandbox Code Playgroud)

它等于:

>>> d = {}
>>> for i in range(5):
...     d[i] = i**2
>>> d
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
Run Code Online (Sandbox Code Playgroud)

是否(i for i in range(5))给一个元组?不!,它是一个生成器表达式.返回一个生成器:

>>> (i for i in range(5))
<generator object <genexpr> at 0x7f52703fbca8>
Run Code Online (Sandbox Code Playgroud)

它与以下相同:

>>> def gen():
...     for i in range(5):
...         yield i
>>> gen()
<generator object gen at 0x7f5270380db0>
Run Code Online (Sandbox Code Playgroud)

你可以用它作为发电机:

>>> gen = (i for i in range(5))
>>> next(gen)
0
>>> next(gen)
1
>>> list(gen)
[2, 3, 4]
>>> next(gen)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
StopIteration
Run Code Online (Sandbox Code Playgroud)

注意:如果在函数内使用列表推导,则不需要[]if该函数可以循环生成器.例如,sum():

>>> sum(i**2 for i in range(5))
30
Run Code Online (Sandbox Code Playgroud)

相关(关于生成器):了解Python中的生成器.

  • @AChampion:是的,我在我的回答中提到过,因为我在学习列表理解时尝试了`[我在x中,如果我在其他时候]",它不起作用.经过一些研究后,我明白我必须使用`[我,如果我在其中为我而在x中]`.所以我想如果我在这里提到它,那么其他人可以避免我以前遇到过的问题. (3认同)

cdl*_*ane 7

有列表,字典和集合理解,但没有元组理解(尽管探索"生成器表达式").

它们解决了Python中的传统循环是语句(不返回任何内容)而不是返回值的表达式的问题.

它们不是每个问题的解决方案,可以重写为传统循环.当需要在迭代之间维护和更新状态时,它们变得很尴尬.

它们通常包括:

[<output expr> <loop expr <input expr>> <optional predicate expr>]
Run Code Online (Sandbox Code Playgroud)

但可以用许多有趣和奇怪的方式扭曲.

它们可以类似于Python中仍然存在并继续使用的传统map()filter()操作.

如果做得好,他们的满意度很高.

  • 这使我的一天:"做得好,他们有很高的满意度." (3认同)

Dav*_*ove 6

如果您更喜欢以更直观的方式来了解正在发生的事情,那么这可能会有所帮助:

# for the example in the question...

y = []
for x in range(10):
    y += [x**2]

# is equivalent to...

y = [x**2 for x in range(10)]

# for a slightly more complex example, it is useful
# to visualize  where the various x's end up...

a = [1,2,3,4]
b = [3,4,5,6]
c = []

for x in a:
          if x in b:
                  c += [x]
#   \         \        /
#    \    _____\______/
#     \  /      \
#      \/        \
#      /\         \
#     /  \         \
#    /    \         \
c = [x for x in a if x in b]

print(c)
Run Code Online (Sandbox Code Playgroud)

...产生输出[3, 4]


Mat*_*ith 5

我最近看到了很多关于列表理解如何工作的困惑(关于其他 SO 问题和来自同事的)。一点数学教育可以帮助解释为什么语法是这样的,以及列表推导式的真正含义。

语法

最好将列表推导式视为集合/集合上的谓词,就像我们在数学中使用集合构建器符号一样。这种符号对我来说实际上感觉很自然,因为我拥有数学本科学位。但是忘记我吧,Guido van Rossum(Python 的发明者)拥有数学硕士学位并有数学背景。

设置生成器符号速成课程

以下是 set builder 符号如何工作的(非常基础的):

在此处输入图片说明

所以,这个集合构建器表示法表示严格为正的数字集合(即[1,2,3,4,...])。

混淆点

1) set builder notation 中的谓词过滤器只指定我们想要保留的项目,列表理解谓词也做同样的事情。您不必包含用于省略项目的特殊逻辑,除非包含在谓词中,否则它们会被省略。空谓词(即最后没有条件)包括给定集合中的所有项目。

2)集合构建器表示法中的谓词过滤器放在最后,列表推导式中也类似。(一些)初学者认为类似的东西[x < 5 for x in range(10)]会给他们列表[0,1,2,3,4],而实际上它输出[True, True, True, True, True, False, False, False, False, False]. 我们得到的输出[True, True, True, True, True, False, False, False, False, False],因为我们要求Python来评估x < 5所有的项目range(10)。没有谓词意味着我们从集合中获得所有东西(就像在集合构建器符号中一样)。

如果您在使用列表推导式时将 set builder 符号记在脑后,它们会更容易接受。

哼!


归档时间:

查看次数:

4792 次

最近记录:

6 年,2 月 前