# python之迭代器与生成器

## 迭代器

### 创建一个迭代器

``````class Demo(object):
def __iter__(self):
# 需要返回一个迭代器，否则无法进行for...in循环
# MyIterator 要重写  __next__ 方法以后，它就是一个迭代器
it = MyIterator()
return it

class MyIterator(object):
count = 0

def __next__(self):
if self.count < 5:
self.count += 1
return 'hello world'
else:
raise StopIteration  # 抛出一个StopIteration异常

d = Demo()
# print(isinstance(d, Iterable))
for i in d:
print(i)``````

### 如何判断一个对象是否可以迭代

``````In [50]: from collections import Iterable

In [51]: isinstance([], Iterable)
Out[51]: True

In [52]: isinstance({}, Iterable)
Out[52]: True

In [53]: isinstance('abc', Iterable)
Out[53]: True

In [54]: isinstance(mylist, Iterable)
Out[54]: False

In [55]: isinstance(100, Iterable)
Out[55]: False``````

### 迭代器的应用场景(斐波那契迭代器实现)

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...

``````class FibIterator(object):
"""斐波那契数列迭代器"""
def __init__(self, n):
"""
:param n: int, 指明生成数列的前n个数
"""
self.n = n
# current用来保存当前生成到数列中的第几个数了
self.current = 0
# num1用来保存前前一个数，初始值为数列中的第一个数0
self.num1 = 0
# num2用来保存前一个数，初始值为数列中的第二个数1
self.num2 = 1

def __next__(self):
"""被next()函数调用来获取下一个数"""
if self.current < self.n:
num = self.num1
self.num1, self.num2 = self.num2, self.num1+self.num2
self.current += 1
return num
else:
raise StopIteration

def __iter__(self):
"""迭代器的__iter__返回自身即可"""
return self

if __name__ == '__main__':
fib = FibIterator(10)
for num in fib:
print(num, end=" ")``````

## 生成器

### 创建生成器方法1

``````In [15]: L = [ x*2 for x in range(5)]

In [16]: L
Out[16]: [0, 2, 4, 6, 8]

In [17]: G = ( x*2 for x in range(5))

In [18]: G
Out[18]: <generator object <genexpr> at 0x7f626c132db0>

In [19]:``````

``````In [15]: L = [ x*2 for x in range(5)]

In [16]: L
Out[16]: [0, 2, 4, 6, 8]

In [17]: G = ( x*2 for x in range(5))

In [18]: G
Out[18]: <generator object <genexpr> at 0x7f626c132db0>

In [19]:
Copy

In [19]: next(G)
Out[19]: 0

In [20]: next(G)
Out[20]: 2

In [21]: next(G)
Out[21]: 4

In [22]: next(G)
Out[22]: 6

In [23]: next(G)
Out[23]: 8

In [24]: next(G)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-24-380e167d6934> in <module>()
----> 1 next(G)

StopIteration:

In [25]:
In [26]: G = ( x*2 for x in range(5))

In [27]: for x in G:
....:     print(x)
....:
0
2
4
6
8

In [28]:``````

### 创建生成器方法2

generator非常强大。如果推算的算法比较复杂，用类似列表生成式的 for 循环无法实现的时候，还可以用函数来实现。

``````class FibIterator(object):
"""斐波那契数列迭代器"""
def __init__(self, n):
"""
:param n: int, 指明生成数列的前n个数
"""
self.n = n
# current用来保存当前生成到数列中的第几个数了
self.current = 0
# num1用来保存前前一个数，初始值为数列中的第一个数0
self.num1 = 0
# num2用来保存前一个数，初始值为数列中的第二个数1
self.num2 = 1

def __next__(self):
"""被next()函数调用来获取下一个数"""
if self.current < self.n:
num = self.num1
self.num1, self.num2 = self.num2, self.num1+self.num2
self.current += 1
return num
else:
raise StopIteration

def __iter__(self):
"""迭代器的__iter__返回自身即可"""
return self``````

``````In [38]: for n in fib(5):
....:     print(n)
....:
1
1
2
3
5

In [39]:``````

``````In [39]: g = fib(5)

In [40]: while True:
....:     try:
....:         x = next(g)
....:         print("value:%d"%x)
....:     except StopIteration as e:
....:         print("生成器返回值:%s"%e.value)
....:         break
....:
value:1
value:1
value:2
value:3
value:5

In [41]:``````

## 总结

• 使用了yield关键字的函数不再是函数，而是生成器。（使用了yield的函数就是生成器）
• yield关键字有两点作用：
• 保存当前运行状态（断点），然后暂停执行，即将生成器（函数）挂起
• 将yield关键字后面表达式的值作为返回值返回，此时可以理解为起到了return的作用
• 可以使用next()函数让生成器从断点处继续执行，即唤醒生成器（函数）
• Python3中的生成器可以使用return返回最终运行的返回值，而Python2中的生成器不允许使用return返回一个返回值（即可以使用return从生成器中退出，但return后不能有任何表达式）。