龙空技术网

生成器表达式和列表推导式

南冠客蓬莱 153

前言:

而今咱们对“表达式生成器怎么用”大约比较讲究,姐妹们都想要分析一些“表达式生成器怎么用”的相关知识。那么小编在网上汇集了一些有关“表达式生成器怎么用””的相关文章,希望小伙伴们能喜欢,我们快快来了解一下吧!

迭代器的输出有两个很常见的使用方式,1) 对每一个元素执行操作,2) 选择一个符合条件的元素子集。比如,给定一个字符串列表,你可能想去掉每个字符串尾部的空白字符,或是选出所有包含给定子串的字符串。

列表推导式和生成器表达时让这些操作更加简明,你可以用以下代码去掉一个字符串流中的所有空白字符:

通过列表推导式,你会获得一个 Python 列表;stripped_list 就是一个包含所有结果行的列表,并不是迭代器。生成器表达式会返回一个迭代器,它在必要的时候计算结果,避免一次性生成所有的值。 这意味着,如果迭代器返回一个无限数据流或者大量的数据,列表推导式就不太好用了。 这种情况下生成器表达式会更受青睐。

生成器表达式两边使用圆括号 ("()") ,而列表推导式则使用方括号 ("[]")。生成器表达式的形式为:

( expression for expr in sequence1             if condition1             for expr2 in sequence2             if condition2             for expr3 in sequence3 ...             if condition3             for exprN in sequenceN             if conditionN )

再次说明,列表推导式只有两边的括号不一样(方括号而不是圆括号)。

生成器表达式总是写在圆括号里面,不过也可以算上调用函数时用的括号。如果你想即时创建一个传递给函数的迭代器,可以这么写

obj_total = sum(obj.count for obj in list_all_objects())

其中 for...in 语句包含了将要遍历的序列。这些序列并不必须同样长,因为它们会从左往右开始遍历,而 不是 同时执行。对每个 sequence1 中的元素,sequence2 会从头开始遍历。sequence3 会对每个 sequence1sequence2 的元素对开始遍历。

换句话说,列表推导式器是和下面的 Python 代码等价:

这说明,如果有多个 for...in 语句而没有 if 语句,输出结果的长度就是所有序列长度的乘积。如果你的两个列表长度为3,那么输出的列表长度就是9:

为了不让 Python 语法变得含糊,如果 expression 会生成元组,那这个元组必须要用括号括起来。下面第一个列表推导式语法错误,第二个则是正确的:

# Syntax error[x, y for x in seq1 for y in seq2]# Correct[(x, y) for x in seq1 for y in seq2]

列表推导式可以利用 range 区间、元组、列表、字典和集合等数据类型,快速生成一个满足指定需求的列表。

列表推导式的语法格式如下:

[表达式 for 迭代变量 in 可迭代对象 [if 条件表达式] ]

此格式中,[if 条件表达式] 不是必须的,可以使用,也可以省略。

通过列表推导式的语法格式,明显会感觉到它和 for 循环存在某些关联。其实,除去 [if 条件表达式] 部分,其余各部分的含义以及执行顺序和 for 循环是完全一样的(表达式其实就是 for 循环中的循环体),即它的执行顺序如下所示:

for 迭代变量 in 可迭代对象    表达式

初学者可以这样认为,它只是对 for 循环语句的格式做了一下简单的变形,并用 [] 括起来而已,只不过最大的不同之处在于,列表推导式最终会将循环过程中,计算表达式得到的一系列值组成一个列表。

上面代码的第 3 行会对 a_range 执行迭代,由于 a_range 相当于包含 10 个元素,因此程序生成的 a_list 同样包含 10 个元素,且每个元素都是 a_range 中每个元素的平方(由表达式 x*x 控制)

不仅如此,我们还可以在列表推导式中添加 if 条件语句,这样列表推导式将只迭代那些符合条件的元素。例如如下代码:

第一行代码与程序一中第 3 行代码大致相同,只是为这里给列表推导式增加了 if 条件语句,这会导致推导式只处理 range 区间的偶数,因此程序生成的 b_list 只包含 5 个元素。

另外,以上所看到的列表推导式都只有一个循环,实际上它可使用多个循环,就像嵌套循环一样。例如如下代码:

d_list = [(x, y) for x in range(5) for y in range(4)]print(d_list)

输出结果为

[(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3),  (2, 0), (2, 1), (2, 2), (2, 3), (3, 0), (3, 1), (3, 2), (3, 3),  (4, 0), (4, 1), (4, 2), (4, 3)]此处为了排版整齐,实际结果是没有换行的

上面代码中,x 是遍历 range(5) 的迭代变量(计数器),因此该 x 可迭代 5 次;y 是遍历 range(4) 的计数器,因此该 y 可迭代 4 次。因此,该(x,y)表达式一共会迭代 20 次。上面的 for 表达式相当于如下嵌套循环:

当然,也支持类似于三层嵌套的 for 表达式,例如如下代码:

对于包含多个循环的 for 表达式,同样可指定 if 条件。假如我们有一个需求:程序要将两个列表中的数值按“能否整除”的关系配对在一起。比如 src_a 列表中包含 30,src_b 列表中包含 5,其中 30 可以整除 5,那么就将 30 和 5 配对在一起。对于上面的需求使用 for 表达式来实现非常简单。例如如下代码。

虽然列表推导能够用来初始化元组,数组或者其他序列类型,但是生成器表达式是更好的选择。因为生成器表达式遵守迭代器协议,是逐个生产出元素,而不是创建一个完整的列表,然后把列表传递到某个构造函数中。两者比较,显然是生成器表达式更节约内存。

生成器表达式的语法与列表推导类似,只是将方括号换成圆括号。

示例用生成器表达式初始化元组

letters = 'abcdefg'tuple(ord(letter) for letter in letters)

输出为

(97, 98, 99, 100, 101, 102, 103)

注意:如果生成器表达式是一个函数调用过程中的唯一参数,那么不需要额外在用括号将它们围起来。

标签: #表达式生成器怎么用 #表达式生成器可以用来书写什么 #生成器表达式的结果是什么