生成器
列表推导式:直接生成列表
List1=[x for x in range[1,11]]
print(List1)
生成器
什么是生成器?
通过列表生成式,我们可以直接创建一个列表,但是,受到内存限制,列表容量肯定是有限的,而且创建一个包含 100 万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的 list,从而节省大量的空间,在 Python 中,这种一边循环一边计算的机制,称为生成器:generator
生成器是一个特殊的程序,可以被用作控制循环的迭代行为,python 中生成器是迭代器的一种,使用 yield 返回值函数,每次调用 yield 会暂停,而可以使用 next()函数和 send()函数恢复生成器。
生成器类似于返回值为数组的一个函数,这个函数可以接受参数,可以被调用,但是,不同于一般的函数会一次性返回包括了所有数值的数组,生成器一次只能产生一个值,这样消耗的内存数量将大大减小,而且允许调用函数可以很快的处理前几个返回值,因此生成器看起来像是一个函数,但是表现得却像是迭代器
python 中的生成器
要创建一个 generator,有很多种方法,第一种方法很简单,只有把一个列表生成式的[]中括号改为()小括号,就创建一个 generator
# 列表生成式
lis = [x*x for x in range(10)]
print(lis)
# 生成器
generator_ex = (x*x for x in range(10))
print(generator_ex)
结果:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
<generator object at 0x000002A4CBF9EBA0>
那么创建 lis 和 generator_ex,的区别是什么呢?从表面看就是[ ]和(),但是结果却不一样,一个打印出来是列表(因为是列表生成式),而第二个打印出来却是 at 0x000002A4CBF9EBA0>,那么如何打印出来 generator_ex 的每一个元素呢?
如果要一个个打印出来,可以通过 next()函数获得 generator 的下一个返回值:
# 生成器
generator_ex = (x*x for x in range(10))
print(next(generator_ex))
print(next(generator_ex))
print(next(generator_ex))
print(next(generator_ex))
print(next(generator_ex))
print(next(generator_ex))
print(next(generator_ex))
print(next(generator_ex))
print(next(generator_ex))
print(next(generator_ex))
print(next(generator_ex))
结果:
0
1
4
9
16
25
36
49
64
81
Traceback (most recent call last):
File "列表生成式。py", line 42, in
print(next(generator_ex))
StopIteration
大家可以看到,generator 保存的是算法,每次调用 next(generaotr_ex)就计算出他的下一个元素的值,直到计算出最后一个元素,没有更多的元素时,抛出 StopIteration 的错误,而且上面这样不断调用是一个不好的习惯,正确的方法是使用 for 循环,因为 generator 也是可迭代对象:
# 生成器
generator_ex = (x*x for x in range(10))
for i in generator_ex:
print(i)
结果:
0
1
4
9
16
25
36
49
64
81
所以我们创建一个 generator 后,基本上永远不会调用 next(),而是通过 for 循环来迭代,并且不需要关心 StopIteration 的错误,generator 非常强大,如果推算的算法比较复杂,用类似列表生成式的 for 循环无法实现的时候,还可以用函数来实现。
比如著名的斐波那契数列,除第一个和第二个数外,任何一个数都可以由前两个相加得到:
1,1,2,3,5,8,12,21,34.....
斐波那契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:
#fibonacci 数列
def fib(max):
n,a,b =0,0,1
while n < max:
a,b =b,a+b
n = n+1
print(a)
return 'done'
a = fib(10)
print(fib(10))
也就是说上面的函数也可以用 generator 来实现,上面我们发现,print(b)每次函数运行都要打印,占内存,所以为了不占内存,我们也可以使用生成器,这里叫 yield。如下:
def fib(max):
n,a,b =0,0,1
while n < max:
yield b
a,b =b,a+b
n = n+1
return 'done'
a = fib(10)
print(fib(10))
print([i for i in a])
yield 函数可以让当前函数停下来,等需要调用的时候再执行,资源消耗最小的。
欢迎来到testingpai.com!
注册 关于