迭代相关:__iter__函数和__next__函数
__ iter__函数和__next__函数
迭代器就是重复地做一些事情,可以简单的理解为循环,在python中实现了__iter__方法的对象是可迭代的,实现了next()方法的对象是迭代器,这样说起来有点拗口,实际上要想让一个迭代器工作,至少要实现__iter__方法和next方法。很多时候使用迭代器完成的工作使用列表也可以完成,但是如果有很多值列表就会占用太多的内存,而且使用迭代器也让我们的程序更加通用、优雅、pythonic。
如果一个类想被用于for ... in循环,类似list或tuple那样,就必须实现一个__iter__()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的next()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。
容器(container):
容器是用来储存元素的一种数据结构,容器将所有数据保存在内存中,Python中典型的容器有:list,set,dict,str等等。
class test():
def __init__(self,data=1):
self.data = data
def __iter__(self):
return self
def __next__(self):
if self.data > 5:
raise StopIteration
else:
self.data+=1
return self.data
for item in test(3):
print(item)
输出结果:
4
6
for … in… 这个语句其实做了两件事。第一件事是获得一个可迭代器,即调用了__iter__()函数。 第二件事是循环的过程,循环调用__next__()函数。
对于test这个类来说,它定义了__iter__和__next__函数,所以是一个可迭代的类,也可以说是一个可迭代的对象(Python中一切皆对象)。
迭代器:
含有__next__()函数的对象都是一个迭代器,所以test也可以说是一个迭代器。如果去掉__itet__()函数,test这个类也不会报错。如下代码所示:
class test():
def __init__(self,data=1):
self.data = data
def __next__(self):
if self.data > 5:
raise StopIteration
else:
self.data+=1
return self.data
t = test(3)
for i in range(3):
print(t.__next__())
输出结果:
4
6
生成器:
生成器是一种特殊的迭代器。当调用fib()函数时,生成器实例化并返回,这时并不会执行任何代码,生成器处于空闲状态,注意这里prev, curr = 0, 1并未执行。然后这个生成器被包含在list()中,list会根据传进来的参数生成一个列表,所以它对fib()对象(一切皆对象,函数也是对象)调用__next__方法。
def fib(end = 1000):
prev,curr=0,1
while curr < end:
yield curr
prev,curr=curr,curr+prev
print(list(fib()))
输出结果:
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987]
上面只是做了几个演示,这里具体说明一下:
当调用iter函数的时候,生成了一个迭代对象,要求__iter__必须返回一个实现了__next__的对象,我们就可以通过next函数访问这个对象的下一个元素了,并且在你不想继续有迭代的情况下抛出一个StopIteration的异常(for语句会捕获这个异常,并且自动结束for),下面实现了一个自己的类似range函数的功能。
class MyRange(object):
def __init__(self, end):
self.start = 0
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.start < self.end:
ret = self.start
self.start += 1
return ret
else:
raise StopIteration
from collections.abc import *
a = MyRange(5)
print(isinstance(a, Iterable))
print(isinstance(a, Iterator))
for i in a:
print(i)
输出结果是:
True
4
接下来我们使用
next
函数模拟一次:
class MyRange(object):
def __init__(self, end):
self.start = 0
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.start < self.end:
ret = self.start
self.start += 1
return ret
else:
raise StopIteration
a = MyRange(5)