迭代器 生成器
迭代器
for 循环就使用了迭代器协议,将数据转化为迭代器。
迭代器是访问集合内元素的一种方式,一般用来遍历数据。
迭代器访问与列表的下标访问不同,迭代器是不能返回的,迭代器提供了一种惰性获取数据的方式
[]使用了 __getitem__
迭代协议即实现了 __iter__
方法
collections.abc.Iterable
可迭代类即实现了 __iter__
方法
collections.abc.Iterator
迭代器即实现了 __iter__
__next__
方法
class Group(object):
'''实现一个迭代器对象'''
def __init__(self, employee_list:list):
self.iter_list = employee_list
self.index = 0
def __iter__(self):
return self
def __next__(self):
# 返回迭代值的函数
try:
word = self.iter_list[self.index]
except IndexError:
raise StopIteration
生成器
有 yield
就是一个生成器函数,返回一个生成器对象。
生成器对象内部实现了迭代器。
def fib2(index):
re_list = []
n, a, b = 0, 0, 1
while n < index:
re_list.append(b)
a, b = b, a+b
n += 1
return re_list
# 遇到 yield 就返回一个值,之后继续运行函数
def gen_fib(index):
n, a, b = 0, 0, 1
while n < index:
yield b
a, b = b, a+b
n += 1
# print(fib2(500))
for i in gen_fib(100):
print(i)
python一切皆对象,栈帧对象,字节码对象
用函数调用子函数时会创建一个栈帧
所有的栈帧都是分配在堆内存上的,这决定了栈帧可以独立于调用者存在
当foo函数调用bar函数时,在堆上创建了两个栈帧对象。
生成器对二者进行了封装
f_lasti
记录代码上一次运行到的位置
f_locals
记录局部变量
前两者能够控制函数的运行与暂停。是协程的基础。
collections.UserList
是一个用python实现的列表对象。其中__iter__
就是使用生成器实现的。
生成器使用案例
# 案例:读取一个 500G 的文件,只有一行,通过特殊字符作为分隔符
def myreadlinew(f, newline):
buf = ""
while True:
while newline in buf:
pos = buf.index(newline)
yield buf[:pos]
buf = buf[pos + len(newline)]
chunk = f.read(4096*10)
if not chunk: # 读到文件结尾
yield buf
break
buf += chunk
with open("file.txt") as f:
for line in myreadlinew(r, "分隔符"):
print(line)