迭代器 生成器

迭代器

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)
posted @ 2021-01-20 10:03  某某人8265  阅读(42)  评论(0编辑  收藏  举报