可迭代的对象、迭代器和生成器
1.理论
1.所有Python序列都可以迭代
2.语言内部使用iter()内置函数处理可迭代对象
3.若没有实现iter()但是实现了__getitem__方法, Python会创建一个迭代器尝试迭代
迭代原理
a = [1, 2]
for i in a:
print(i)
等价于
a = [1, 2]
result = iter(a)
print(next(result))
print(next(result)) 当迭代完所有元素后,再次迭代会报错
此时迭代器为空,重新获取迭代器才可以迭代
print(next(result)) 结果与上述相同
Python从可迭代的对象中获取迭代器 result = iter(a) a 是可迭代的对象, result是迭代器
2.典型的迭代器
class Sen:
""
生产可迭代对象
""
def __init__(self, words):
self.words = words
def __iter__(self): 实现迭代方法
return SenIter(self.words)
class SenIter:
""
迭代器
""
def __init__(self, words):
self.words = words
self.index = 0
def __next__(self):
try:
word = self.words[self.index]
except IndexError:
raise StopIteration()
self.index += 1
return word
def __iter__(self):
return self 返回迭代器本身
obj = Sen([1, 2, 3])
for i in obj:
print(i)
1 2 3
可迭代的对象须有__iter__方法,每次都实例化一个新的迭代器,不能实现__next__方法
迭代器需实现__next__方法以及__iter__方法,迭代器一直可以迭代
3.生成器函数
class Sen:
def __init__(self, words):
self.words = words
def __iter__(self): 生成器函数
for word in self.words:
yield word
return
功能相同,此时迭代器是生成器对象,每次调用__iter__方法都会自动创建
__iter__方法是生成器函数
生成器也是迭代器,工作原理如下
def gen():
yield 1
yield 2
yield 4
result = gen()
print(next(result))
print(next(result))
print(next(result))
1 2 4
4.生成器表达式
优点:随取随用,节省内存
只有在进行迭代时才读取,惰性机制
实现一个等差数列
def gg(begin, step, end):
result = type(begin+step)(begin) 赋值并类型转换
forever = end is None 若为None则认定为无穷数列
index = 0
while forever or result < end:
yield result
index += 1
result = begin + step * index
res = gg(1, 1/3, end=None) 迭代则输出
利用标准库实现
import itertools
def gg(begin, step, end):
first = type(begin+step)(begin)
ap = itertools.count(first, step) 生成迭代器
if end is not None:
ap = itertools.takewhile(lambda x: x < end, ap) 限制结束点
return ap
res = gg(1, 1/3, 2)
5.初识 yield from
1.yield from 能代替内层的for循环,节省代码量
2.创建通道,把内层生成器直接与外层生成器的客户端联系起来
代码
def chain(*it):
for i in it: 等价于 for i in it:
yield from i for j in i:
yield j
s = 'abc'
t = range(3)
print(list(chain(s, t)))
['a', 'b', 'c', 0, 1, 2]
6.iter函数的另一种用法
from random import randint
def d():
return randint(1, 6)
res = iter(d, 1) 第一个参数必须是可调用的对象,不断产值
for i in res: 第二个参数是标记值,当可调用对象返回这个值时程序退出
print(i)
3 2 5 5
一个意外小测试
对于 any 和 all函数来说,这两个函数会短路,即一确定结果就立即停止使用迭代器
g = (n for n in [0, 0.0, 6, 9]) 一个生成器
print(any(g)) 循环到 6 得到结果,立即停止
print(next(g)) 输出下一个值 9
若在最后一个值得到结果则返回结果,抛出停止迭代
Finally 生成器实现斐波那契数列
def f():
a, b = 0, 1
while True:
time.sleep(0.5) 便于观察
yield a
a, b = b, a + b
for i in f():
print(i)