生成器(generator)
列表是python中经常使用的一种数据类型,但是受到内存的限制,其容量是有限的。当列表中的元素很多很多的时候,可能会出现内存不够,列表无法建立的情况,而且即使我们可以开辟成功,我们使用的元素也可能是其中很小的一部分元素,这样在很大程度上就浪费了内存。
为了解决这个问题,python引入了“生成器”(generator)这个概念,其实质就是“一边循环,一边计算”的机制,即:,即当用户需要使用某个对象时,python才根据事先设计好的规则开辟内存空间创建该对象供用户使用,而不是像列表一样事先将所有的对象都创建完毕之后再提供给用户使用。
下面我们来总结一下生成器的创建方式。
生成器创建方式
要使用生成器就得知道它是怎么建立的,一般有以下两种方式:
1、生成器推导式
在讨论这个方式之前,我们需要了解一下列表推导式。
知识补充:列表推导式
列表推导式的作用就是在原有列表的基础上,经过一系列的操作,得到新的列表。其格式如下:
新列表=[表达式 for 变量 in 旧列表]
eg:
一般还有两种升级方式:
(1)方式1:
新列表=[表达式 for 变量 in 旧列表 if 条件]
eg:
(2)方式2:
新列表=[结果A if 条件 else 结果B for 变量 in 旧列表]
eg:
看完了列表推导式,我们就可以在这个基础上使用第一种方式创建生成器了。具体方式就是将列表推导式使用的 [] 换成 () 就行了。
如下:
(1)新列表=(表达式 for 变量 in 旧列表)
(2)新列表=(表达式 for 变量 in 旧列表 if 条件)
(3)新列表=(结果A if 条件 else 结果B for 变量 in 旧列表)
此时,我们需要知道,用上面三个式子得到的结果不是list类型,而是生成器(generator)。
举个例子看看(结果可以和上面的图进行对比):
总结:
[]——列表(list)
()——生成器(generator)
2、函数+yield关键字
在函数中使用yield关键字后,该函数就成了一个生成器,那么yield关键字是什么呢?
yield关键字:
yield指令可以暂停一个函数并返回其中间结果,使用该指令的函数将保存执行环境,并在必要时恢复
即:我们可以认为yield=return+暂停
那么用这种方式创建生成器的格式是什么样子呢?
def func():
...
yield
...
g=func()#g就是创建的生成器
eg:
以上就是创建生成器的两种方式。那么我们得到了生成器之后,怎么使用呢?怎么得到里面的元素呢?
得到生成器的元素
我们有三种方法可以得到生成器的元素,如下:
1、next()
next()方式是系统提供的,其格式如下:
next(g)
eg:
def func():
count=0
while count<100:
temp=yield count
print(temp)
count=count+1
g=func()#g就是创建的生成器
print(next(g))
print(next(g))
print(next(g))
print(next(g))
注意
此处的None是由next方法的系统实现决定的,如下:
2、_ _ next _ _()
_ _ next _ _()方法是生成器方法,其作用是返回生成器的下一次调用,格式如下:
g.__next__()
eg:
def func():
count=0
while count<100:
temp=yield count
print(temp)
count=count+1
g=func()#g就是创建的生成器
print(g.__next__())
print(g.__next__())
print(g.__next__())
print(g.__next__())
print(g.__next__())
注意
对于普通的生成器,第一个__next__()方法的调用相当于启动生成器,此时会从生成器函数的第一行开始执行,直到第一次执行完yield语句后,跳出生成器函数。
当调用第二个__next__()方法后,会重新进入生成器函数,并从yield语句的下一条语句开始执行,直到重新运行到yield语句,执行后再次跳出生成器函数。
后面的__next__()方法调用以此类推。
3、send()
send()方法是生成器方法,其作用是接受外部传入的一个变量,并根据变量内容计算结果返回到生成器函数中,格式如下:
g.send()
第一次调用send()时,必须使用__next__()或是send(None),不能使用send发送一个非None的值给生成器函数,否则会出错,因为没有yield语句来接收这个值。
eg:
def func():
count=0
while count<5:
temp=yield
print(temp)
count=count+1
g=func()#g就是创建的生成器
# print(g.__next__())
print(g.send(None))
print(g.send(5))
print(g.send(9))
print(g.send(8))
注意:
在使用send()和_ _ next _ _()方法时,可能会遇到异常——StopIteration,其出现的原因是生成器的元素已经全部生成,没有元素可供继续生成了,所以在我们使用这两个函数的时候,要注意生成器是否还有元素可以供我们生成,建议添加异常提示信息,比如可以使用return语句进行返回异常提示信息。
def func():
count=0
while count<2:
temp=yield
print(temp)
count=count+1
return "没有元素可供生成!"
g=func()#g就是创建的生成器
# print(g.__next__())
print(g.send(None))
print(g.send(5))
print(g.send(9))
print(g.send(8))
print(g.send(7))