Python 之推导式

  • Post author:
  • Post category:python



目录


语法


分类


列表推导式


集合推导式


字典推导式


推导式(comprehensions),又称解析式,是 Python 中常见的语法糖。推导式可以从一个数据序列构建另一个新的数据序列,常用于数据处理场景。

语法

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

其中

if

条件判断根据需要,可有可无。

推导式的核心为 for 循环。根据返回对象的不同,推导式可区分为列表推导式,字典推导式,结合推导式等。不同推导式在语法上基本一致。

分类

列表推导式

列表推导式(list comprehension)是一种简化的 for 循环创建列表,为最常见的推导式。


例 1

>>> l = []
>>> for i in range(5):
        l.append(i)
>>> l
[0, 1, 2, 3, 4]

上述 for 循环转换为列表推导式则为:

>>> l = [l for l in range(5)]
>>> l
[0, 1, 2, 3, 4]

可见,与单纯 for 循环相比,作为语法糖,列表推导式简化了代码,返回新的列表。

列表推导式也可以应用于相对复杂的场景:


例 2

>>> evens = [i for i in range(10) if i % 2 == 0]
>>> evens
[0, 2, 4, 6, 8]


例 3

>>> l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> l = [l[i][i] for i in range(len(l))]
>>> l
[1, 5, 9]


例 4

>>> l = [lambda x: x* i for i in range(3)]
>>> type(l[0]), "---", l[0])
<class 'function'> --- <function <listcomp>.<lambda> at 0x7f9e19ab00>
>>> l[1](2)
4

更可以实现复杂的嵌套循环:


例 5

>>> matrix = [
    [1, 2, 3], 
    [4, 5, 6], 
    [7, 8, 9]
]
>>> l = [i for row in matrix for i in row]
>>> l
[1, 2, 3, 4, 5, 6, 7, 8, 9]

若以 for 循环来表示,则为:

>>> matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
]

>>> l = []

>>> for row in matrix:
        for i in row:
            l.append(i)
>>> l
[1, 2, 3, 4, 5, 6, 7, 8, 9]


例 6

>>> l = [x**y+z for x in range(2) for y in range(3) for z in range(4)]
>>> l
[1, 2, 3, 4, 0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]


例 7

>>> names = [['Billy', 'Jefferson', 'Andrew', 'Wesley', 'Joe'],
         ['Steven', 'Alice', 'Jennifer', 'Eva', 'Sherry']]
>>> print([name for i in names for name in i if name.count('e') >= 2])
['Jefferson', 'Wesley', 'Steven', 'Jennifer']


例 8

>>> matrix = [
    [1, 2, 3], 
    [4, 5, 6], 
    [7, 8, 9]
]
>>> print([[row[i] for row in matrix] for i in range(3)])
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]

该例嵌套了内外循环,等价于

>>> l = []
>>> matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]
>>> for i in range(3):
        temp = []
        for row in matrix:
            temp.append(row[i])
        l.append(temp)
>>> print(l)

通过上述示例,可见:

  • 列表推导式遍历顺序为自右而左,先遍历 for 后的可迭代对象,然后根据 for 前的表达式进行运算,最终生成新的列表。
  • 如果有 if 条件语句,for 遍历后即进行条件判断。
  • 如果有多个 for 循环,则最终的对象个数为多个 for 循环的笛卡尔积。
  • 嵌套的列表推导式,与嵌套 for 循环的原理相同。

毋庸置疑,列表推导式以一行代码之简,挽多行代码之繁。但正如一个硬币有其两面, 多个表达式和可迭代对象融入一行代码,不可避免带来可读性降低的问题,有时甚至晦涩难懂,且出错后难以排查。且随着一行代码的延长,甚至超过代码规范的长度(一般为80个字符),更使得代码的理解变得困难。因此,适可而止是为上策。

有时,面对长长的推导式,可采用断行的方式予以处理,以便理解。


例 2

evens = [
    i 
    for i in range(10) 
    if i % 2 == 0
]


例 7

[
    name 
    for i in names 
    for name in i 
    if name.count('e') >= 2
]

如果把列表推导式的

[]

替换为

()

,则变为

生成器(generator )表达式


例 8

>>> g = ( i for i in range(6))
>>> g
<generator object <genexpr> at 0x7f7f201e00>
>>> list(g)
[0, 1, 2, 3, 4, 5]
>>> list(g)
[]

生成器推导式与列表推导式的区别在于:

  • 生成器表达式一次遍历,随后清空生成器对象,因此比列表推导式速度更快,占用的内存也更少。
  • 返回值不同。列表推导式返回新列表。生成器表达式返回生成器对象。

生成器表达式的返回结果可以根据需要转化为列表或元组,也可以 for 或 __next__() 方法或内置函数 next() 遍历:


例 9

>>> g = (i for i in '上帝与你同在')
>>> for i in g:
        print(i)
    
上
帝
与
你
同
在

>>> g = (i for i in '上帝与你同在')
>>> next(g)
'上'
>>> next(g)
'帝'
>>> g.__next__()
'与'
>>> g.__next__()
'你'

集合推导式

集合推导式跟列表推导式非常相似,唯一区别在于用

{}

代替

[]


例 10

>>> S = {x for x in range(10) if x % 2 == 0}
>>> S
{0, 2, 4, 6, 8}


例 11

>>> names = ['Billy', 'Jefferson', 'Andrew', 'Wesley', 'Joe']
>>> S = {name[0] for name in names}
>>> S
{'A', 'W', 'B', 'J'}

字典推导式

字典推导式为列表推导式思想的延续,语法差不多,只不过返回的是字典而已。


例 12

>>> d = {'a': 1, 'b': 2, 'c': 3}
>>> print({d[k]: k for k in d})
{1: 'a', 2: 'b', 3: 'c'}


例 13

>>> d = {'a': 4, 'B': 3, 'c': 2, 'D':1}
>>> print({i.lower(): d.get(i.lower(), 0) + d.get(i.upper(), 0) for i in d.keys()})
{'a': 4, 'b': 3, 'c': 2, 'd': 1}


注:

1、关于语法糖,请参见:



Python 之语法糖


手到擒来的快感



https://blog.csdn.net/iprobobo/article/details/123568839



2、关于列表,请参见:



Python 序列之三言两语


序列是具有先后关系的一组元素…



https://blog.csdn.net/iprobobo/article/details/122542937


3、关于集合,请参见:



Python 集合之 abc


集合之合集



https://blog.csdn.net/iprobobo/article/details/122511498


4、关于字典,请参见:



Python 字典之演义


映射无处不在,键值对无处不在。



https://blog.csdn.net/iprobobo/article/details/122668767




版权声明:本文为iprobobo原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。