Python列表生成器

目录

概述

我们都知道列表解析式具有运行效率高,代码简洁等优点,但是它是一次性生成整个列表,对于内存空间的占用极大,想要节约内存,就需要使用列表生成器,它就像range函数一样,不是一次性生成整个列表,而是每次迭代按需产生一个对象。

1、生成器函数

外表看上去像是一个函数,但是没有用return语句一次性的返回整个结果对象列表,取而代之的是使用yield语句一次返回一个结果。

运行过程分析

常规函数接受输入的参数然后立即送回单个结果,之后这个函数调用就结束了。

但生成器函数却不同,他通过yield关键字返回一个值后,还能从其退出的地方继续运行,因此可以随时间产生一系列的值。他们自动实现了迭代协议,并且可以出现在迭代环境中。

运行的过程是这样的:生成器函数返回一个迭代器,for循环等迭代环境对这个迭代器不断调用next函数,不断的运行到下一个yield语句,逐一取得每一个返回值,直到没有yield语句可以运行,最终引发StopIteration异常。看,这个过程是不是很熟悉。

def squre(num):
    for i in range(num):
        yield i**2

S = squre(5)
print(S)
print(iter(S))
print(next(S))
print(next(S))
print(next(S))
print(next(S))

输出结果:
<generator object squre at 0x000001C53CEC47D8>
<generator object squre at 0x000001C53CEC47D8>
0
1
4
9

在for循环中使用

for i in squre(5):
    print(i, end=' ')

输出结果:
0 1 4 9 16

状态保存

在每次循环的时候,生成器函数都会在yield处产生一个值,并将其返回给调用者,即for循环。然后在yield处保存内部状态,并挂起中断退出。在下一轮迭代调用时,从yield的地方继续执行,并且沿用上一轮的函数内部变量的状态,直到内部循环过程结束。

def squre(num):
    for x in range(num):
        yield x**2
        print('x = {}'.format(x))

for x in squre(5):
    print('x**2 = {}'.format(x))
    print('-------------')

输出结果:
x**2 = 0
-------------
x = 0
x**2 = 1
-------------
x = 1
x**2 = 4
-------------
x = 2
x**2 = 9
-------------
x = 3
x**2 = 16
-------------
x = 4

不难发现,生成器函数计算出x的平方后就挂起退出了,但他仍然保存了此时x的值,而yield后的print语句会在for循环的下一轮迭代中首先调用,此时x的值即是上一轮退出时保存的值。

2、生成器表达式

类似于列表解析,但是方括号换成了圆括号,他们返回按需产生的一个结果对象,而不是构建一个结果列表。

使用方法

print([x for x in range(5)])
print((x for x in range(5)))

输出结果:
[0, 1, 2, 3, 4]
<generator object <genexpr> at 0x000001C53D084360>

可以看到方括号是熟悉的列表解析式,一次性返回整个列表,圆括号是生成器表达式,返回一个生成器对象,而不是一次性生成整个列表

用于迭代

列表生成式可适用于迭代

lst = [1,2,3,4,5,6]
for i in (x for x in lst):
    print(i, end=',')

输出结果:
1,2,3,4,5,6

其他的例子

lst = [3,4,1,0,-1,2]
print(sorted((x**2 for x in lst), reverse=True))

输出结果:
[16, 9, 4, 1, 1, 0]

集合生成器对象

集合解析式等效于将生成器对象传入到list、set、dict等函数中作为构造参数

set(f(x) for x in S if P(x))
{f(x) for x in S if P(x)}

猜你喜欢

转载自blog.csdn.net/MSDN_tang/article/details/81121914
今日推荐