迭代器(Iterator):能用 next( )方法取值的对象,用 iter( )方法可以从可迭代对象(序列、生成器)中返回一个迭代器。值得 注意的是,迭代器是访问可迭代对象的一种方式,他只能往前取值,不能回取。
迭代器图解如下图所示:
实际上,for item in iterable 循环的本质:先通过iter( )方法获取可迭代对象iterable 的迭代器Iterator,然后对获取的可迭代对象不断用next( )方法来获取下一个item,当遇到StopIteration 的异常时结束循环,因此有:
说明:并不是只有for循环可以接受可迭代对象,此外还有像list( )、tuple( )等也能接收可迭代对象,比如b = list(a),这个语句不要单纯以为只是类型转换,其本质是list( )首先生成一个空列表b,然后用iter( )方法获得可迭代对象a的迭代器,然后用next( )方法依次取出a中的值然后填入到空列表b中。
可迭代对象:能用iter( )方法返回迭代器的对象,需要注意的是,可迭代对象内部需要定义iter( )方法来返回迭代器对象。常见有:字符串、列表、元组、字典、集合、字节串、字节数组等。
下面给出自定义的可迭代对象和迭代器代码(两个类实现):
from collections import Iterable
from collections import Iterator
# 可迭代对象类
class Classmate(object):
def __init__(self):
self.names = list()
def add(self, name):
self.names.append(name)
def __iter__(self):
return ClassIterator(self)
# 迭代器类
class ClassIterator(object):
def __init__(self, obj):
self.obj = obj
self.current_num = 0
def __iter__(self):
pass
def __next__(self):
if self.current_num < len(self.obj.names):
ret = self.obj.names[self.current_num]
self.current_num += 1
return ret
else:
raise StopIteration
classmate = Classmate()
for i in range(3):
classmate.add(i)
print(isinstance(classmate, Iterable)) # --->Ture,证明了classmate是可迭代对象
print(isinstance(classmate, Iterator)) # --->False,证明了classmate不是迭代器对象
classmate_iterator = iter(classmate)
# classmate将自动调用Classmate类中的实例方法iter(),iter()方法返回一个ClassIterator(self)
# 类对象,也即有等式成立:classmate_iterator = ClassIterator(classmate),此时的obj即为
# classmate。在for temp in classmate语句中,首先classmate类调用iter()方法返回一个
# ClassIterator类,然后ClassIterator调用next()方法,逐个取值赋给temp。
print(isinstance(classmate_iterator, Iterator)) # --->True,证明了classmate_iterator是迭代器对象
for x in classmate:
for y in classmate:
print((x,y),end=' ')
# --->print将输出:(0, 0) (0, 1) (0, 2) (1, 0) (1, 1) (1, 2) (2, 0) (2, 1) (2, 2)
大家可以考虑将Classmate(object)类中的__next__()方法替换为如下函数,看看上面的输出结果将会有什么改变:
# 情形一:
def __next__(self):
current_num = 0
ret = self.obj.names[current_num]
current_num += 1
return ret
# 情形二:
def __next__(self):
if self.current_num < len(self.obj.names):
ret = self.obj.names[self.current_num]
self.current_num += 1
return ret
下面给出自定义可迭代对象和迭代器的代码(一个类实现):
from collections import Iterable
from collections import Iterator
class Classmate(object): # 可迭代对象类、迭代器类
def __init__(self):
self.names = list()
self.current_num = 0
def add(self, name):
self.names.append(name)
def __iter__(self):
return self
def __next__(self):
if self.current_num < len(self.names):
ret = self.names[self.current_num]
self.current_num += 1
return ret
else:
raise StopIteration
classmate = Classmate()
for i in range(3):
classmate.add(i)
print(isinstance(classmate, Iterable)) # --->True,证明了classmate是可迭代对象
print(isinstance(classmate, Iterator)) # --->True,证明了classmate是迭代器对象
classmate_iterator = iter(classmate)
print(isinstance(classmate_iterator, Iterator)) # --->True,证明了classmate_iterator是迭代
# 器对象
for x in classmate:
for y in classmate:
print((x,y),end=' ') # 这里将输出为:(0, 1) (0, 2)
下面给出一个高效率程序,用迭代器实现斐波那契数列的编程方法(依据迭代器的特性——用的时候才生成,大大提高了效率,节省CPU和RAM):
class Fibonacci(object):
def __init__(self,end):
self.ends = end
self.current_num = 0
self.first = 0
self.second = 1
def __iter__(self):
return self
def __next__(self):
if self.current_num < self.ends:
self.temp = self.first
self.first, self.second = self.second, self.first + self.second
self.current_num += 1
return self.temp
else:
raise StopIteration
fibonacci = Fibonacci(10)
for i in fibonacci:
print(i)
生成器(Generator):一种可以简单有效的创建迭代器的工具,也可以说生成器是一种特殊的迭代器,可以用next( )或者send( )方法对其取值。
生成器的类型:生成器函数和生成器表达式。
生成器函数:一般来说,含有yield语句的函数,此函数在被调用时返回一个生成器对象,例如:range( )。
yield语句格式:yield 表达式
作用:yield语句用于def函数中,目的是将此函数作为生成器函数使用,yield用来生成数据,供迭代器的next( )方法使用。yield一个重要的应用就是,可以随时调用yield语句,那么程序会暂停,并且返回yield后面的值,一般在爬虫上应用较多。
生成器函数说明:
1,在生成器函数内调用return会产生一个StopIteration异常,不会往后执行;
2,带有yield的函数不仅仅只用于for循环中,也可以用于某个函数的参数,只要这个函数的参数是可迭代的;
3,yield是一个类似于return的关键字,迭代一次遇到yield就返回表达式的内容,并且程序会暂停至此处,直到有send( )或者是next( )方法去解等待,重点是:下一次迭代时,从上一次迭代遇到的yield后面的代码开始执行。
4,生成器是可迭代的,但是只可以读取他一次,因为用的时候才生成,大大提高了效率,节省CPU和RAM。
生成器表达式:(表达式 for 变量 in Iterable [ if 真值表达式])
下面给出利用生成器完成斐波那契数列的代码:
def cerate_num(all_num):
a, b = 0, 1
current_num = 0
while current_num < all_num:
yield a # 当执行到此词句时,程序暂停,首先把值a传递给num,然后当for循环继续从cerate_num取值
# 时,程序从yield a开始往后执行程序,而不是从头开始。
a, b = b, a+b
current_num += 1
generator = cerate_num(10)
for num in generator:
print(num)