“列表理解”及其类似概念是什么意思?它如何工作以及如何使用它?

2024-11-18 08:41:00
admin
原创
16
摘要:问题描述:我有以下代码:[x ** 2 for x in range(10)] 当我在 Python shell 中运行它时,它返回:[0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 我搜索了一下,似乎这被称为列表推导,类似地,似乎还有集合/字典推导和生成器表达式。但它是如何工作的呢?...

问题描述:

我有以下代码:

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

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

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

我搜索了一下,似乎这被称为列表推导,类似地,似乎还有集合/字典推导和生成器表达式。但它是如何工作的呢?


解决方案 1:

来自文档

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


关于您的问题,列表推导与以下“简单”的 Python 代码的作用相同:

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

你怎么才能用一行写出来呢?嗯...我们可以...可能...map()使用lambda

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

但仅使用列表推导不是更清晰、更简单吗?

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

基本上,我们可以用 做任何事情x。不仅限于x**2。例如,运行 的方法x

>>> [x.strip() for x in ('foo
', 'bar
', 'baz
')]
['foo', 'bar', 'baz']

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

>>> [int(x) for x in ('1', '2', '3')]
[1, 2, 3]

例如,我们还可以将其用作对象x的键dict。让我们看看:

>>> d = {'foo': '10', 'bar': '20', 'baz': '30'}
>>> [d[x] for x in ['foo', 'baz']]
['10', '30']

组合一下怎么样?

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

等等。


您还可以在列表推导中使用ifif...else。例如,您只希望 中的奇数range(10)。您可以这样做:

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

啊,太复杂了。那么下一个版本呢?

>>> [x for x in range(10) if x%2]
[1, 3, 5, 7, 9]

要使用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]

你听说过嵌套列表推导式吗?你可以在一个列表推导式中放入两个或更多个for列表。例如:

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

我们先讨论第一部分,for x in [[1, 2, 3], [4, 5, 6]]它给出[1, 2, 3][4, 5, 6]。然后,for i in x给出123456

警告:你总是需要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

我们还有集合理解字典理解生成器表达式

集合推导和列表推导基本相同,但前者返回一个集合而不是一个列表

>>> {x for x in [1, 1, 2, 3, 3, 1]}
{1, 2, 3}

它与以下内容相同:

>>> set([i for i in [1, 1, 2, 3, 3, 1]])
{1, 2, 3}

字典推导式 看起来像集合推导式,但是它使用{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}

它等于:

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

(i for i in range(5))给出一个元组吗?不!这是一个生成器表达式。它返回一个生成器

>>> (i for i in range(5))
<generator object <genexpr> at 0x7f52703fbca8>

它与以下内容相同:

>>> def gen():
...     for i in range(5):
...         yield i
>>> gen()
<generator object gen at 0x7f5270380db0>

您可以将其用作生成器:

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

注意:如果你在函数中使用列表推导,则不需要[]该函数是否可以循环遍历生成器。例如sum()

>>> sum(i**2 for i in range(5))
30

相关(关于生成器):理解 Python 中的生成器。

解决方案 2:

有列表、字典和集合理解,但没有元组理解(尽管确实探索了“生成器表达式”)。

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

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

它们通常包括:

[<output expr> <loop expr <input expr>> <optional predicate expr>]

但可以以很多有趣和奇异的方式扭曲。

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

如果做得好,他们会有很高的满意度。

解决方案 3:

如果你更喜欢用更直观的方式来了解发生了什么,那么也许这会有所帮助:

# 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]
#                    /
#        ___________/
#       /      \n#      /        \n#      /         \n#     /           \n#    /             \nc = [x for x in a if x in b]

print(c)

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

解决方案 4:

最近我看到很多人对列表推导的工作原理感到困惑(在其他 SO 问题上以及同事那里)。一点点数学知识可以帮助你理解为什么语法是这样的,以及列表推导的真正含义。

语法

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

集合构建器符号速成课程

以下是集合构建器符号的工作原理(非常基础):

在此处输入图片描述

因此,这个集合构造器符号表示严格为正数的一组数字(即[1,2,3,4,...])。

容易混淆的地方

1)集合构建器表示法中的谓词过滤器仅指定我们要保留哪些项,列表理解谓词做同样的事情。您不必包含省略项的特殊逻辑,除非谓词包含它们,否则它们将被省略。空谓词(即末尾没有条件)包括给定集合中的所有项。

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

如果在使用列表推导时心里记住集合构建器符号,它们就会更容易被接受。

呼呼!

解决方案 5:

介绍

列表推导式是在 Python 中创建列表的一种高级声明式方法。列表推导式的主要优点是可读性和可维护性。很多人觉得列表推导式非常易读,甚至从未见过列表推导式的开发人员通常也能正确猜出它的含义。

# Snippet 1
squares = [n ** 2 for n in range(5)]

# Snippet 2
squares = []
for n in range(5):
    squares.append(n ** 2)

这两段代码都会产生squares等于的结果[0, 1, 4, 9, 16]

请注意,在第一个代码片段中,您输入的是声明所需的列表类型,而第二个代码片段则指定如何创建列表。这就是为什么理解是高级且声明性的。

句法

[EXPRESSION for VARIABLE in SEQUENCE]

EXPRESSION是任意 Python 表达式,但其中通常包含一些变量。此变量在VARIABLE字段中说明。SEQUENCE定义变量枚举的值的来源。

考虑代码片段 1 [n ** 2 for n in range(5)]

  • EXPRESSIONn ** 2

  • VARIABLEn

  • SEQUENCErange(5)

请注意,如果你检查类型,squares你会发现列表推导只是一个常规列表:

>>> type(squares)
<class 'list'>

有关 EXPRESSION 的更多信息

表达式可以是任何能简化为一个值的东西:

  • 算术表达式,例如n ** 2 + 3 * n + 1

  • 函数调用就像f(n)使用n变量一样

  • 切片操作如下s[::-1]

  • 方法调用bar.foo()

  • ...

一些例子:

>>> [2 * x + 3 for x in range(5)]
[3, 5, 7, 9, 11]
>>> [abs(num) for num in range(-5, 5)]
[5, 4, 3, 2, 1, 0, 1, 2, 3, 4]
>>> animals = ['dog', 'cat', 'lion', 'tiger']
>>> [animal.upper() for animal in animals]
['DOG', 'CAT', 'LION', 'TIGER']

筛选:

最终列表中元素的顺序由 的顺序决定SEQUENCE。但是,您可以通过添加子句来过滤掉元素if

[EXPRESSION for VARIABLE in SEQUENCE if CONDITION]

CONDITION是一个计算结果为True或 的表达式False。从技术上讲,该条件不必依赖于VARIABLE,但通常会使用它。

例子:

>>> [n ** 2 for n in range(5) if n % 2 == 0]
[0, 4, 16]
>>> animals = ['dog', 'cat', 'lion', 'tiger']
>>> [animal for animal in animals if len(animal) == 3]
['dog', 'cat']

另外,请记住,Python 允许您编写除了列表之外的其他类型的推导式:

  • 字典推导

  • 集合推导

解决方案 6:

对于那些寻找嵌套内联运算符的人来说:

[(i,j) for i in range(8) for j in range(8)]

这相当于itertools.product

from itertools import product

list(product(range(8), range(8)))

对于其他上下文,这相当于以下嵌套循环:

results = []
for i in range(8):
    for j in range(8):
        coord = (i, j)
        results.append(coord)
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用