1. 程式人生 > 實用技巧 >迭代器 生成器

迭代器 生成器

迭代器

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)