1,可迭代对象iterator,迭代器iterator,生成器generator
可迭代对象iterable:实现了__iter__方法的类,iter()方法可以从iterable中获取iterator。
迭代器Iterator:1)实现__iter__方法(返回自己)和__next__(获取值)方法的类。2)生成器。
生成器generator:含yeild,生成器属于迭代器。
上述三种类型都可作用于for循环。
list、dict、str虽然是iterable,却不是iterator,为什么呢?因为iterator表示的是一个数据流,可以被next()调用不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把数据流看作一个序列,但我们无法提前知道序列长度,只有不断通过next()进行下一个计算。iterator甚至可以表示无限大的数据流,list不可能无限大。
2,可迭代对象与迭代器的关系
关于可迭代与迭代器的关系,具体实现细节可参考“3实现可迭代的方法”中的经典版方法。
s = 'abcdefg' # s是个iterator,<class 'str'>
s可以被迭代:
for i in s: print(i)
迭代的本质是从iterable获取iterator(iterable的__iter__方法return了一个iterator),然后再不断使用iterator的next()方法获取值:
sit = iter(s) # it是个iterator,<class 'str_iterator'> while True: try: print(next(sit)) except StopIteration: break
判断是否可迭代,iterable和iterator都可以被迭代:
isinstance(s, collections.Iterable) # True isinstance(sit, collections.iterable) # True
但s不能被next,sit可以被next,因为s是iterable没有__next__,sit是iterator具有__next__
3,实现对象可迭代的方法
实现一个序列类型,接受输入值x,返回从x到11的值。
3.1,方法一:python序列鸭子类型
python在尝试迭代对象时,找不到__iter__就会去调用__getitem__,__getitem__实现从0开始的索引取值即可
class Foo: def __init__(self, data): self.data = data def __getitem__(self, i): return range(self.data, 11)[i]
3.2,方法二:经典版
iterable+iterator,构建Foo的iterator,缺点是代码量大。
关键点:iterable的__iter__返回iterator;iterator的__iter__返回self,__next__逐个取值。
class Foo: def __init__(self, data): self.data = data def __iter__(self): # iterable中的__iter__返回iterator return Foo_iterator(self.data) class Foo_iterator: def __init__(self, data): self.data = data def __iter__(self): # iterator中的__iter__返回自己 return self def __next__(self): # iterator实现__next__ if self.data > 10: raise StopIteration else: num = self.data self.data += 1 return num
看看Foo的实例和返回的iterator:
f = Foo(1) fit = iter(f) print(type(f)) # <class '__main__.Foo'> print(type(fit)) # <class '__main__.Foo_iterator'>
对比下内置的iterable类,是不是完全一致:
s = 'abc' sit = iter(s) print(type(s)) # <class 'str'> print(type(sit)) # <class 'str_iterator'> r = range(10) rit = iter(r) print(type(r)) # <class 'range'> print(type(rit)) # <class 'range_iterator'>
3.3,方法三:糟糕版
Foo自己实现__next__和__iter__,让Foo既是iterable,也是自己的iterator,糟糕不推荐
class Foo: def __init__(self, data): self.data = data def __iter__(self): return self def __next__(self): if self.data > 10: raise StopIteration else: num = self.data self.data += 1 return num
3.4,方法四:generator版
用generator实现iterable中的__iter__方法
class Foo: def __init__(self, data): self.data = data def __iter__(self): for i in range(self.data, 11): yield i
看看Foo的实例和返回的iterator,发现iter()返回了一个generator:
f = Foo(1) fit = iter(f) print(type(f)) # <class '__main__.Foo'> print(type(fit)) # <class 'generator'>
备注:Foo中的__iter__获取数据时,用的是惰性获取range(非惰性就是list(range(self.data, 11)))。一般推荐用惰性函数实现,例如用finditer替代findall。
3.5,方法五:生成器表达式
class Foo: def __init__(self, data): self.data = data def __iter__(self): return (i for i in range(self.data, 11))
4,生成器函数
待补充