python中iterator,iterable与generator的区别
python中,一个类型是否是一个iterator或iterable由以下两个类方法决定:__iter__(self)和__next__(self)
__iter__(self)要返回一个iterator类型,而list,dict,tuple这些都是iterable类型,不过可以用iter函数把它变成iterator。如果__iter__(self)正确定义了,那么这个类型就是iterable,这意味着可以用for循环遍历。
__next__(self)返回什么都可以(不过定义最好是有意义的,而且最好有溢出检测,next调用本身是没有检测的)。如果__next__(self)正确定义了,那么这个类型就可以用next来遍历了,而且也可以用for循环遍历,不过不可以用iter函数把它变成iterator。
如果__iter__(self)和__next__(self)都正确定义了,那么这个类型就是iterator。
还有一个重要的方法__getitem__(self,index),这里index就是下标。只有正确定义了这个类函数,这个类型才可以用下标遍历,也可以用for循环遍历,还可以用iter函数把它变成iterator。但是这个类型不是iterable,更不用说iterator。
如果想让一个类型是一个generator,我只知道两种方法:
第一种是用yield,第二种用类似列表生成式的样子:
a=(i for i in range(10))
generator是iterator,iterator是iterable。
测试代码:
from collections import Iterator,Iterable,Generator
class test_iter():
def __init__(self):
self.data=[1,2,3,4,5]
self.len=len(self.data)
self.point=-1
# 以下四种分别独立
def __iter__(self): #返回一个iterator,正确定义了这个函数就是可迭代的(iterable)
return iter(self.data)
def __next__(self): #正确定义了后可以使用next方法访问,可以用for循环,__iter__和__next__定义了都才是iterator
if self.point<self.len-1:
self.point+=1
return self.data[self.point]
else:
raise Exception('out of range.')
def gen(self): #用yield方法生成的就是generator,generator是iterator,不可以下标访问,(x for x in range(10))这样写出来的也是generator,这样写出来的比起列表生成式有好处,是惰性计算,需要时才会计算,节省内存。
for i in range(self.len):
yield self.data[i]
def __getitem__(self,x): #正确定义了这个,既不是iterable也不是iterator,但是可以用下标访问,也可以用for循环,可以用iter转换为一个iterator
return self.data[x]
if __name__=='__main__':
a=test_iter()
print(isinstance(a,Iterable))
print(isinstance(a,Iterator))
print(isinstance(a,Generator))