生成器
生成器,利用迭代器我们可以在每次迭代获取数据时(通过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=" ")
# [0, 1, 4, 9, 16, 25]
# <generator object <genexpr> at 0x00000203CCED0DB0>
# 通过next()函数取得下一个值
# 0
# 1
# 4
# 9
# 16
# 25
# 通过for遍历
# 0 1 4 9 16 25 #
生成器函数
在函数中如果出现了yield关键字,那么该函数就不再是一个普通函数而是一个生成器函数,调用该函数,会得到一个生成器对象。
def foo():
yield 1
yield 2
return "Error"
yield 3
f = foo()
print(next(f)) # 程序会停留在对应yield后的语句
print(next(f))
print(next(f)) # 当程序遇到return,return后的语句不会再执行。因此报错。
# 1
# 2
# File "C://生成器.py", line 39, in <module>
# print(next(f)) # 当程序遇到return,return后的语句不会再执行。因此报错。
#StopIteration: Error
next 和 yield 进行匹配。如果遇到return ,return后的语句不会再执行,直接抛出StopIteration,终止迭代。
- 在一个生成器中,如果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))
for i in range(0,6):
print(next(odd_num))
通过类手动编写迭代器,实现类似的效果。
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))
Help on generator object:
odd = class generator(object)
| Methods defined here:
|
| __del__(...)
|
| __getattribute__(self, name, /)
| Return getattr(self, name).
|
| __iter__(self, /)
| Implement iter(self).
|
| __next__(self, /)
| Implement next(self).
|
| __repr__(self, /)
| Return repr(self).
|
| close(...)
| close() -> raise GeneratorExit inside generator.
|
| send(...)
| send(arg) -> send 'arg' into generator,
| return next yielded value or raise StopIteration.
|
| throw(...)
| throw(typ[,val[,tb]]) -> raise exception in generator,
| return next yielded value or raise StopIteration.
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| gi_code
|
| gi_frame
|
| gi_running
|
| gi_yieldfrom
| object being iterated by yield from, or None
None
- close()
def gen():
yield 1
yield 2
yield 3
yield 4
g = gen()
print(next(g))
print(next(g))
g.close()
print(next(g)) # 回溯
- send()
- x = yield y 语句的含义: send()的作用就是使x赋值为其所传送的值(send的参数),然后让生成器执行到下一个yield。
- 如果生成器未启动,则必须在使用send()前启动生成器,启动的方法:gen.next()或gen.send(None)执行到第一个yield处。之后就可以使用send(para)不断的传入值。
- 如果是已启动,则send(para)的作用就是给x赋值为发送的值(send的参数),然后让生成器执行到下一个yield。
def gen():
value = 0
while True:
receive = yield value
if receive == "e":
break
value = "got: %s "% receive
g = gen()
print(g.send(None))
print(g.send("aaa"))
print(g.send(123))
# 0
# got: aaa
# got: 123
print(g.send("e")) # 结束
# Traceback (most recent call last):
# 0
# File "C:/Users/ou/PycharmProjects/untitled/day01/0730/生成器.py", line 95, # in <module>
# print(g.send("e"))
# StopIteration
# got: aaa
# got: 123
def gen():
i = 0
while i < 5:
temp = yield i
print(temp)
i += 1
obj = gen()
print(next(obj)) # 返回yield后的值,停止!
print(next(obj))
print(obj.send("city")) # 从上次停止处开始, 即给temp赋值,如不赋值,但发生器已启动默认为None
# 0
# None
# 1
# city
# 2
- throw()
- 手动抛出异常:在生成器暂停的地方抛出类型为
type
的异常,并返回下一个yield
的返回值。
- 手动抛出异常:在生成器暂停的地方抛出类型为
def gen():
i = 0
while i < 5:
temp = yield i
i += 1
print(temp)
obj = gen()
print(next(obj)) # 0
print(next(obj)) # 1
print(next(obj))# 2
print(obj.throw(Exception, "Method throw called!"))
# Traceback (most recent call last):
# 0
# File "C://生成器.py", line 110, in <module>
# None
# print(obj.throw(Exception, "Method throw called!"))
# 1
# File "C://生成器.py", line 102, in gen
# None
# temp = yield i
# 2
# Exception: Method throw called!