迭代器,生成器
迭代器
一个类,如果实现:
- 实现
__iter__(self)
方法,并返回自身self
- 实现
__next__(self)
方法,返回迭代的值。
举例:
from collections.abc import Iterator,Iterable
class it(object):
def __init__(self, num):
self.num = num
def __iter__(self):
return self
def __next__(self):
self.num += 1
# 大于10,抛出异常
if self.num > 10:
raise StopIteration
return self.num
ge = it(1)
print(isinstance(ge,Iterable))
print(isinstance(ge,Iterator))
可迭代对象
实现了 __iter__(self)
, 返回一个迭代器,就是一个可迭代对象。
iter()
可以将一个可迭代对象转变成一个迭代器。
from collections.abc import Iterator,Iterable
class it(object):
def __iter__(self):
return iter([1,2,3])
ge = it(1)
print(isinstance(ge,Iterable))
print(isinstance(ge,Iterator))
生成器
使用 yield
关键字,可以实现生成器, 而且可以直接使用 next()
class generator(object):
def __init__(self, num):
self.num = num
def __iter__(self):
while self.num < 10:
yield self.num
self.num += 1
ge = generator(1)
print(type(ge))
print(isinstance(ge,Iterable))
print(isinstance(ge,Iterator))
当然,上面是一个生成器类,其实生成器跟 __iter__()
没啥太大关系,只要随便使用一个函数,使用 yield
关键字就行了:
def generator():
yield 1
g = generator()
print(g)
生成器的 next(), send(), yield from
next(generator)
很简单,就是不停的执行从当前代码,执行到下一个 yield
处,返回当前 yield 的数据
send(msg)
可以给生成器发送数据,进行数据交互,然后执行到下一个 yield
处,返回 yield 的数据。如果没有可以用来接收数据的变量,则和 next(generator)
效果一样。生成器没有启动时,第一次使用 send()
,必须先发送一个 send(None)
,因为此时还没有 yield 表达式可以来接收值。
yield from <generator>
它可以让两个生成器交互。可以从当前生成器,进入到另一个生成器执行,执行完毕后,再回到当前生成器。
def inner():
print('enter inner')
value = yield 2 # 第二次截止到: yield 2 ; # 第三次从赋值开始: value = send传递过来的值
print('inner value:',value)
yield 3 # 第三次完毕
return 'inner_return' # 第四次开始
def outer():
print('outer entered')
yield 1 # 第一次截至到这里
value = yield from inner() # 第二次起始:进入另一个生成器
yield 4 # 第四次结束
print('back to outer') # 第五次开始
print('value is :', value) # 第五次结束,并抛出 StopIteration 异常
o = outer()
print(next(o)) # 没啥好说的,往下走
print(next(o)) # 没啥好说的,往下走到 yield 2
print(next(o)) # 没法发送数据,所以 yield 2 前面的 value 会是 None
print(next(o)) # 没啥好说的,不停的往下走
print(next(o)) # 没啥好说的,不停的往下走
# ==================================================
o = outer()
print(o.send(None)) # o.send(None) 等同于 next(o),第一次必须发送 None,先走到 yield 代码处
print(o.send('HH')) # 尽管发了一个数据:HH,但是第1次 yield 1 前面没有接收这个数据的变量,所以直接走向下一个 yield
print(o.send('HHH')) # 上一次 yield 停止的地方:value = yield 2 有个变量可以接收值,所以给 value 赋值,然后走到下一个 yield 处
print(o.send('HHHH'))
print(o.send('HHHHH'))
for 循环
for 循环,可以循环迭代器,生成器,可迭代对象。它的原理,就是先执行要循环的对象的__iter__()
方法,获得一个迭代器,然后执行迭代器的 __next__()
方法,并且在循环完毕时,处理一下 StopIteration
异常。虽然我们写函数式的生成器时没有__iter__()
方法,但是它已经内置了这个方法。
譬如:
def it():
yield 1
ge = it()
print(dir(ge))
i = ge.__iter__()
print(dir(i))
print(next(i))
class it(object):
def __iter__(self):
return iter([1,2,3])
# ------- for --------
for i in it():
print(i)
# ------- 原理 --------
i = it().__iter__()
while True:
try:
print(next(i))
except StopIteration:
break