python基础(5)迭代器与生成器
迭代器与生成器
迭代器
迭代器是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
迭代器有两个基本的方法:iter()
和 next()
。
字符串,列表或元组对象都可用于创建迭代器:
>>> list=[1,2,3,4]
>>> it = iter(list) # 创建迭代器对象
>>> print (next(it)) # 输出迭代器的下一个元素
1
>>> print (next(it))
2
迭代器对象可以使用常规for
语句进行遍历:
list4=["hello","this","is","jimmy"]
it=iter(list4) # 创建迭代器对象
for i in it:
print(i,end=" ")
输出结果如下:
hello this is jimmy
自己通过class
类来创建一个迭代器
把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__()
与 __next__()
。
如果你已经了解的面向对象编程,就知道类都有一个构造函数,Python
的构造函数为 __init__()
, 它会在对象初始化的时候执行。
更多内容查阅:Python3 面向对象
__iter__()
方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__()
方法并通过 StopIteration
异常标识迭代的完成。
__next__()
方法(Python 2
里是 next()
)会返回下一个迭代器对象。
创建一个返回数字的迭代器,初始值为 1,逐步递增 2:
class MyNumber:
def __iter__(self):
self.a=1
return self
def __next__(self):
x=self.a
self.a+=2
return x
myclass=MyNumber()
myiter=iter(myclass)
for i in range(5):
print(next(myiter))
执行输出结果:
生成器
在 Python
中,使用了 yield
的函数被称为生成器(generator
)。
我们先抛开 generator
,以一个常见的编程题目来展示 yield
的概念。
斐波那契(Fibonacci
)數列是一个非常简单的递归数列,除第一个和第二个数外,任意一个数都可由前两个数相加得到。用计算机程序输出斐波那契數列的前 N
个数是一个非常简单的问题,许多初学者都可以轻易写出如下函数:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
def fab(max):
n, a, b = 0, 0, 1
while n < max:
print b
a, b = b, a + b
n = n + 1
fab(5)
结果没有问题,但有经验的开发者会指出,直接在 fab
函数中用 print
打印数字会导致该函数可复用性较差,因为 fab
函数返回 None
,其他函数无法获得该函数生成的数列。
要提高 fab
函数的可复用性,最好不要直接打印出数列,而是返回一个 List
。以下是 fab
函数改写后的第二个版本:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
def fab(max):
n, a, b = 0, 0, 1
L = []
while n < max:
L.append(b)
a, b = b, a + b
n = n + 1
return L
for n in fab(5):
print n
改写后的 fab
函数通过返回 List
能满足复用性的要求,但是更有经验的开发者会指出,该函数在运行中占用的内存会随着参数 max
的增大而增大,如果要控制内存占用,最好不要用 List
第三个版本:yield
#!/usr/bin/python
# -*- coding: UTF-8 -*-
def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b # 使用 yield
# print b
a, b = b, a + b
n = n + 1
for n in fab(5):
print n
1
1
2
3
5
第3
个版本的 fab
和第一版相比,仅仅把 print b
改为了 yield b
,就在保持简洁性的同时获得了 iterable
的效果。调用第3版的 fab
和第二版的 fab
完全一致。
简单地讲,yield
的作用就是把一个函数变成一个 generator
,带有 yield
的函数不再是一个普通函数,Python
解释器会将其视为一个 generator
,调用 fab(5)
不会执行 fab
函数,而是返回一个 iterable
对象!在 for
循环执行时,每次循环都会执行 fab
函数内部的代码,执行到 yield b
时,fab
函数就返回一个迭代值,下次迭代时,代码从 yield b
的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield
。