掘金 后端 ( ) • 2024-05-03 14:43

生成式(Comprehension)是 Python 的一种语法结构,它可以应用于可迭代对象上,通过编写一行代码即可完成多行代码的任务,从而显著提高代码的简洁性和可读性。本文将介绍列表生成式、字典生成式和集合生成式(元组没有生成式,但可以用类似生成式的方式来创建元组)。

列表生成式

列表生成式可以通过一行代码快速生成一个列表,其语法如下:

result = [expression for item in iterable]

  • result:生成的新列表。

  • expression:生成的元素。

  • item:从可迭代对象中取出的元素。

  • iterable:可迭代对象。

例如,要生成 1 到 9 的数字平方的列表,除了使用传统的 for 循环搭配列表外,也可以使用列表生成式来实现。列表生成式[j*j for j in range(1,10)]会依次取出 1 到 9 的数字,然后提供给前面的j,最终生成j*j的结果。

# 传统写法
a = []
for i in range(1, 10):
    a.append(i*i)
print(a)      # [1, 4, 9, 16, 25, 36, 49, 64, 81]

# 使用列表生成式
b = [j*j for j in range(1,10)]
print(b)      # [1, 4, 9, 16, 25, 36, 49, 64, 81]

再看一个例子:假设有一个列表a,需要建立一个新列表b,其中b的每个元素是a列表中最大值与其他元素值的差。使用列表生成式,整个代码会变得非常简洁。

# 传统写法
a = [10,20,30,40,50,60,70,80,90]
b = []
for i in a:
    b.append(max(a) - i)     # 用 a 的最大值减去每个项目
print(b)                   # [80, 70, 60, 50, 40, 30, 20, 10, 0]

# 使用列表生成式
a = [10,20,30,40,50,60,70,80,90]
b = [max(a)-i for i in a]
print(b)                   # [80, 70, 60, 50, 40, 30, 20, 10, 0]

如果需要两层 for 循环才能生成的列表,同样可以使用列表生成式来生成。

# 传统写法
# 将两层 for 循环的 i 和 j 加在一起,变成新列表的项目
a = []
for i in 'abc':
    for j in range(1,4):
        a.append(i + str(j))
print(a)        # ['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3']

# 使用列表生成式
# 两个 for 循环分别产生 i 和 j
a = [i + str(j) for i in 'abc' for j in range(1, 4)]
print(a)        # ['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3']

此外,列表生成式也可以结合 Python 的内置函数,对生成的元素进行处理。下面的代码通过一行列表生成式,就能从二维数组中取出最小值。

# 传统写法
a = [[100, 200, 300, 400, 500], [100, 200, 500, 2, 1]]
b = []
for i in a:
    b.append(min(i))  # 将二维列表中每个列表里的最小值取出,变成新的列表
print(min(b))         # 1,印出新的列表里的最小值

# 使用列表生成式
a = [[100, 200, 300, 400, 500], [100, 200, 500, 2, 1]]
print(min([min(i) for i in a]))   # 1

列表生成式搭配 if

列表生成式不仅可以使用 for 循环快速生成列表,还可以结合 if 判断式,快速筛选并生成对应的内容。下面的代码通过列表生成式,将 if 放在后方,就能直接生成一个偶数的列表。

# 传统写法
a = []
for i in range(1,10):
    if i%2 == 0:
        a.append(i)   # 取出偶数放入变量 a
print(a)              # [2, 4, 6, 8]

# 使用列表生成式
a = [i for i in range(1, 10) if i%2 == 0]
print(a)           # [2, 4, 6, 8]

如果将 if 放在 for 的前面,则必须加上 else,下面的例子会将偶数的元素保留,奇数元素替换成 100。

a = []
for i in range(1,10):
    if i%2 == 0:
        a.append(i)   # 取出偶数放入变量 a
    else:
        a.append(100) # 如果是奇数,将 100 放入变量 a
print(a)          # [100, 2, 100, 4, 100, 6, 100, 8, 100]

a = [i if i%2==0 else 100 for i in range(1, 10)]
print(a)          # [100, 2, 100, 4, 100, 6, 100, 8, 100]

字典生成式

字典生成式可以通过一行代码快速生成一个字典,其语法如下:

result = {key: value for item in iterable}

  • result:生成的新字典。

  • key:生成的键。

  • value:生成的值。

  • item:从可迭代对象中取出的元素。

  • iterable:可迭代对象。

下面的例子会创建一个 key 是迭代元素,value 是迭代元素数值平方的字典。

# 传统写法
a = {}
for i in range(1,10):
    a[i] = i*i   # 将 i*i 对应指定的键
print(a)         # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

# 使用字典生成式
a = {i:i*i for i in range(1,10)}
print(a)       # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

集合生成式

集合生成式可以通过一行代码快速生成一个集合,其语法如下:

result = {value for item in iterable}

  • result:生成的新集合。

  • value:生成的值。

  • item:从可迭代对象中取出的元素。

  • iterable:可迭代对象。

下面的例子会建立一个迭代元素平方的集合。

a = set()
for i in range(1,10):
    a.add(i*i)   # 将 i*i 添加到集合里
print(a)         # {64, 1, 4, 36, 9, 16, 49, 81, 25}

a = {i*i for i in range(1,10)}
print(a)       # {64, 1, 4, 36, 9, 16, 49, 81, 25}

元组 (数组) 生成式

元组没有生成式的语法,但是有类似的方式可以生成元组,其语法为:

variable = tuple(value for item in iterable)

  • variable:类型为 tuple 的变量。

  • value:生成的值。

  • item:从迭代对象里取出的元素。

  • iterable:可迭代的对象。

a = tuple(i for i in range(10))
print(a)   # (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

也可以使用表达式以及 if 判断式生成元组

a = tuple(i*i for i in range(10) if i>5)
print(a)   # (36, 49, 64, 81)