生成器
生成器,利用迭代器,我们可以在每次迭代获取数据时(通过next()方法)按照特定的规律进行生成。但是我们在实现一个迭代器时,关于当前迭代的状态需要我们自己记录,进而才能根据当前的状态生成下一个数据。为了达到记录当前状态,并配合next()函数进行迭代使用,可以采用更简便的语法。
即生成器(generator),生成器是一种特殊的迭代器,它比迭代器更优雅
创建一个生成器
列表[]—>生成器
li=[x**2 for x in range(6)]
print(li)
gen=(x**2 for x in range(6))
print(gen)
print('通过next()函数取得下一个值')
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))
print("通过for遍历")
gen=(x**2 for x in range(6))
for i in gen:
print(i,end=' ')
生成器函数
在函数中如果出现了yield关键字,那么该函数就不再是一个普通函数而是一个生成器函数。
demo:
def foo():
yield 1
yield 2
# return
yield 3
f=foo()
print(next(f))#程序会停留在对应yield后的语句
print(next(f))
print(next(f))#当程序遇到return,return后的语句不会再执行。因此报错
next和yield进行匹配。如果遇到return,return后的语句不会再执行。因此报错
def odd():
n=1
while True:
yield n
n+=2
odd_num=odd()
print(odd_num)
count=0
for i in odd_num:
if count>5:
break
print(i)
count+=1
print(next(odd_num))
print(next(odd_num))
1
3
5
7
9
11
15
17
生成器支持的方法
class OddIter:
def __init__(self):
self.start=-1
def __iter__(self):
return self
def __next__(self):
self.start+=2
return self.start
odd=OddIter()
for i in range(6):
print(next(odd))
print(help(odd))
#运行结果 1,3,5,7,9,11
Help on OddIter in module __main__ object:
class OddIter(builtins.object)
| Methods defined here:
|
| __init__(self)
| Initialize self. See help(type(self)) for accurate signature.
|
| __iter__(self)
|
| __next__(self)
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
None
close()
def gen():
yield 1
yield 2
yield 3
yield 4
yield 5
g=gen()
print(next(g))
print(next(g))
g.close()
print(next(g)) #回溯
1
Traceback (most recent call last):
2
File "D:/py/one/o_tr_2生成器.py", line 71, in <module>
print(next(g)) #回溯
StopIteration
-
send()
-
x=yield y 语句的含义:send()的作用就是使x赋值为其所传送的值(send的参数),然后让生成器执行到下一个yied。
-
如果生成器未启动,则必须在使用send()前启动生成器,而启动的方法可以是gen.next(),也可以是gen.send(None)执行到第一个yield处。之后就可以使用send(para)不断的传入值了。
-
如果是已启动,则send(para)的作用就是给x
赋值发送
#send
def gen():
value=0
while True:
receive=yield value
if receive=='e':
break
value='got: %s'%receive
# receive=yield value 语句的含义:
#send()的作用就是使receive赋值为其所传送的值,然后让生成器执行到下一个yield
g=gen()
print(g.send(None))
print(g.send('aaa'))
print(g.send(123))
print(g.send('e'))
0
Traceback (most recent call last):
got: aaa
got: 123
File "D:/py/one/o_tr_2生成器.py", line 87, in <module>
print(g.send('e'))
StopIteration
def gen():
i=0
while i<5:
temp=yield i
print(i,'+')
print(temp,'-')
i+=1
#创建生成器对象
obj=gen()
#使用next()唤醒生成器
print(next(obj),'--')
print(next(obj),'--')
print(next(obj),'--')
print(obj.send('city'),'--')
print(next(obj),'--')
0 –
0 +
None -
1 –
1 +
None -
2 –
2 +
city -
3 –
3 +
None -
4 –
yied的小结
-
生成器(generator)能够迭代的关键是他有next()方法,工作原理就是通过重复调用next()方法,直到捕获一个异常。
-
带有yield的函数不再是一个普通的函数,而是一个生成器generator,可用于迭代
-
yield是一个类似return 的关键字,迭代一次遇到yield的时候就返回yield后面或者右面的值。而且下一次迭代的时候,从上一次迭代遇到的yield后面的代码开始执行
-
yield就是return返回的一个值,并且记住这个返回的位置。下一次迭代就从这个位置开始。
-
带有yield的函数不仅仅是只用于for循环,而且可用于某个函数的参数,只要这个函数的参数也允许迭代参数。
6. send()和next()的区别就在于send可传递参数给yield表达式,这时候传递的参数就会作为yield表达式的值,而yield的参数是返回给调用者的值,也就是说send可以强行修改上一个yield表达式值。
-
send()和next()都有返回值,他们的返回值是当前迭代遇到的yield的时候,yield后面表达式的值,其实就是当前迭代yield后面的参数。
-
第一次调用时候必须先next()或send(),否则会报错,send后之所以为None是因为这时候没有上一个yield,所以也可以认为next()等同于send(None)