迭代器
说到迭代器就得想说可迭代对象Iterable,实现了__iter__()方法的对象都是可迭代对象,例如很多容器,list ,set, tuples。使用iter方法可以把一个可迭代对象变成迭代器
迭代器是实现了__next__()方法的可迭代对象,也就是说迭代器必须实现__iter__()和__next__()方法,迭代器可以调用next()放不断的迭代,在给定的范围中返回数据,超出范围抛出异常。
几个有趣的例子:
from itertools import count counter = count(start=13) next(counter) 13 next(counter) 14 无限序列只要你愿意可以一直迭代下去,然而你无法创建一个这么大的list是不是可以说的迭代器的优点呢
from itertools import cycle colors = cycle(['red', 'white', 'blue']) print next(colors) # 'red' print next(colors) # 'white' print next(colors) # 'blue' print next(colors) # 'red' 无限循环序列
from itertools import islice,cycle colors = cycle(['red', 'white', 'blue']) limited = islice(colors, 0, 6) for x in limited: print(x)
#有限序列
from itertools import islice class Fib: def __init__(self): self.prev = 0 self.curr = 1 def __iter__(self): return self def __next__(self): #注意在python2中需要写成next() python3中写成__next__() value = self.curr self.curr += self.prev self.prev = value return value f = Fib() print(list(islice(f, 0, 10)))
生成器
简单的生成器(x for x in range(5)) 和列表生成式很像,如果生成的逻辑比较复杂,用类似列表生成式的方式难以表达,我们可以用函数加关键字yield的方式。
在我的理解中,生成器generator是一种特殊的迭代器,他用yield来自动实现了__iter__()和__next__()方法
那我们用yield来实现一下斐波拉契:
def fib(): prev = 0 curr = 1 while True: value = curr yield value curr += prev prev = value a = fib() for x in range(10): print(next(a))
yield
这个yield这么神奇吗?到底该怎么理解它呢?首先你可以把它当成一个return,之后就不再继续往下执行了,调用next()方法后继续执行,举个例子。
def foo(): print("starting...") while True: res = yield 4 print("res:",res) g = foo() print(next(g)) print("*"*20) print(next(g))
starting...
4 # 走到yield 4的时候马上return 4(马上返回并没有赋值操作),
********************
res: None #接着 yield 继续往下走,进行赋值操作,4已经被return 出去了,所以res=None
4 # 进入下一个循环,又走到yield 4
我们稍微修改一下函数
def foo(): print("starting...") while True: res = yield 4 print("res:",res) g = foo() print(next(g)) print("*"*20) print(g.send(7))
starting...
4
********************
res: 7 #挺神奇的怎么变成7了,注意我们此时用的是send()方法,它是传递了一个值给yield表达式,相当于res=7
4
yield from
yield 是从生成器里返回一个元素,那么yield from 从名字上理解就应该是返回一个生成器咯
def foo(): yield from [1,2,3] a = foo() print(next(a)) print(next(a)) print(next(a))
结果:
1
2
3
是不是就可以理解为yield from 返回的是 iter([1,2,3])呢
下面看两个例子
def foo(): for i in range(5): if i == 2: return 'gg' else: yield i a = foo() for i in a: print(i)
0
1
def foo(): for i in range(5): if i == 2: return 'gg' else: yield i a = foo() for i in range(5): print(next(a))
0
1
StopIteration: gg
这是yield的特性,在使用for循环取遍历生成器的时候是不会触发StopIteration异常,使用next()可以触发,如果我们又想用for循环遍历又想触发异常怎么弄,再封装一下
def foo(): for i in range(5): if i == 2: return 'gg' else: yield i def fun(generator): res = yield from generator print(res) a = foo() b = fun(a) for x in b: print(x)
0
1
gg # 捕捉到了异常并且把return 的值给了yield from 表达式