理解Python 3中的列表推导式

介绍

列表推导提供了一种简洁的方式来基于现有列表创建列表。当使用列表推导时,可以利用任何可迭代对象,包括字符串元组来构建列表。

从语法上讲,列表推导包含一个包含表达式的可迭代对象,后面跟着一个for子句。这之后可以跟着额外的forif子句,因此熟悉for循环条件语句将有助于更好地理解列表推导。

列表理解提供了一种替代语法来创建列表和其他顺序数据类型。虽然迭代的其他方法,比如for循环,也可以用来创建列表,但列表理解可能更受欢迎,因为它们可以限制程序中使用的行数。

先决条件

您应该已经安装了Python 3,并在您的计算机或服务器上设置了编程环境。如果您没有设置编程环境,您可以参考适用于您操作系统的本地编程环境的安装和设置指南本地编程环境或适用于您服务器的编程环境(Ubuntu、CentOS、Debian等)的设置指南服务器上的编程环境。

列表理解

在Python中,列表理解的构造方式如下:

信息:要跟着本教程中的示例代码进行操作,请在本地系统上打开Python交互式 shell,运行 python3 命令。然后您可以通过在 >>> 提示后添加、复制或编辑示例来进行操作。

list_variable = [x for x in iterable]

A list, or other iterable, is assigned to a variable. Additional variables that stand for items within the iterable are constructed around a for clause. The in keyword is used as it is in for loops, to iterate over the iterable.

让我们看一个根据字符串创建列表的示例:

shark_letters = [letter for letter in 'shark']
print(shark_letters)

在这里,新列表被赋值给变量 shark_letters,并且 letter 用于代表可迭代字符串 'shark' 中包含的项。

为了确认新列表 shark_letters 的样子,我们调用 print() 并收到以下输出:

Output
['s', 'h', 'a', 'r', 'k']

我们用列表推导式创建的列表由字符串 'shark' 中的项组成,即每个字母都是一个字符串。

列表推导式可以重写为 for 循环,但并非每个 for 循环都能重写为列表推导式。

使用我们上面创建 shark_letters 列表的列表推导式,让我们将其重写为一个 for 循环。这可能有助于我们更好地理解列表推导式的工作原理。

shark_letters = []

for letter in 'shark':
    shark_letters.append(letter)

print(shark_letters)

在使用 for 循环创建列表时,分配给列表的变量需要用空列表初始化,就像代码块的第一行那样。然后,for 循环遍历项目,在可迭代的字符串 'shark' 中使用变量 letter。在 for 循环内部,字符串中的每个项目都使用 list.append(x) 方法添加到列表中。

将列表推导重写为 for 循环可以得到相同的输出:

Output
['s', 'h', 'a', 'r', 'k']

列表推导可以重写为 for 循环,有些 for 循环也可以重写为列表推导,以使代码更简洁。

在列表推导中使用条件语句

列表推导可以利用条件语句来修改现有列表或其他顺序数据类型,在创建新列表时使用。

让我们看一个在列表推导中使用 if 语句的示例:

fish_tuple = ('blowfish', 'clownfish', 'catfish', 'octopus')

fish_list = [fish for fish in fish_tuple if fish != 'octopus']
print(fish_list)

列表推导式使用元组fish_tuple作为新列表fish_list的基础。关键词forin被使用,就像前面的部分中一样,现在添加了if语句。if语句指示仅添加那些不等于字符串'octopus'的项,因此新列表只接收来自元组的不匹配'octopus'的项。

当我们运行这段代码时,我们会注意到fish_list包含与fish_tuple相同的字符串项,除了字符串'octopus'已被省略:

Output
['blowfish', 'clownfish', 'catfish']

因此,我们的新列表包含原始元组的每个项,除了被条件语句排除的字符串。

我们将创建另一个示例,使用数学运算符、整数和range()序列类型。

number_list = [x ** 2 for x in range(10) if x % 2 == 0]
print(number_list)

正在创建的列表number_list将填充每个0-9范围内的项的平方值如果该项的值可被2整除。输出如下:

Output
[0, 4, 16, 36, 64]

为了更详细地解释列表推导的作用,让我们考虑一下如果我们只调用x for x in range(10)会打印出什么。我们的小程序和输出如下:

number_list = [x for x in range(10)]
print(number_list)
Output
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

现在,让我们添加条件语句:

number_list = [x for x in range(10) if x % 2 == 0]
print(number_list)
Output
[0, 2, 4, 6, 8]

if语句已经将最终列表中的项目限制为仅包括那些可以被2整除的项目,省略了所有的奇数。

最后,我们可以添加运算符使每个x的平方:

number_list = [x ** 2 for x in range(10) if x % 2 == 0]
print(number_list)

因此,先前列表中的每个数字[0, 2, 4, 6, 8]现在都被平方了:

Output
[0, 4, 16, 36, 64]

您还可以使用列表推导来复制嵌套的if语句

number_list = [x for x in range(100) if x % 3 == 0 if x % 5 == 0]
print(number_list)

在这里,列表推导将首先检查数字x是否可以被3整除,然后检查x是否可以被5整除。如果x满足两个要求,则会打印,输出为:

Output
[0, 15, 30, 45, 60, 75, 90]

条件if语句可用于控制在创建新列表时包括现有序列中的哪些项目。

列表推导中的嵌套循环

嵌套循环可以用来在我们的程序中执行多次迭代。

这次,我们将回顾一个现有的嵌套for循环结构,并逐步向列表推导式迈进。

我们的代码将创建一个新列表,该列表将遍历2个列表,并根据它们执行数学运算。以下是我们的嵌套for循环代码块:

my_list = []

for x in [20, 40, 60]:
	for y in [2, 4, 6]:
		my_list.append(x * y)

print(my_list)

当我们运行此代码时,会收到以下输出:

Output
[40, 80, 120, 80, 160, 240, 120, 240, 360]

该代码将在每次迭代中将第一个列表中的项与第二个列表中的项相乘。

要将其转换为列表推导式,我们将把代码的每一行压缩成一行,从x * y操作开始。然后是外部for循环,再然后是内部for循环。我们会在列表推导式下方添加一个print()语句,以确认新列表与我们使用嵌套for循环代码块创建的列表相匹配:

my_list = [x * y for x in [20, 40, 60] for y in [2, 4, 6]]
print(my_list)
Output
[40, 80, 120, 80, 160, 240, 120, 240, 360]

我们的列表推导式将嵌套for循环压缩为一行代码,同时仍然创建与分配给my_list变量的完全相同的列表。

列表推导式为我们提供了一种简洁的方法来生成列表,使我们能够将几行代码简化为一行。然而,值得注意的是,代码的可读性始终应该是最重要的,所以当列表推导式的行变得太长或难以处理时,最好将其拆分为循环。

结论

列表推导允许我们将一个列表或其他序列转换为新列表。它们提供了一种简洁的语法来完成这个任务,从而限制了我们的代码行数。

列表推导遵循集合构建符号或集合推导的数学形式,因此对具有数学背景的程序员来说可能特别直观。

尽管列表推导可以使我们的代码更加简洁,但重要的是确保我们的最终代码尽可能易读,因此应避免非常长的单行代码,以确保我们的代码用户友好。

Source:
https://www.digitalocean.com/community/tutorials/understanding-list-comprehensions-in-python-3