生成器函式yield
阿新 • • 發佈:2018-12-06
先看一個栗子:
# -*- coding:UTF-8 -*- __autor__ = 'zhouli' __date__ = '2018/12/6 21:08' # 生成器函式,函式裡只要有yield關鍵字 def gen_func(): yield 1 def func(): return 1 if __name__ == "__main__": gen = gen_func() re = func() pass
生成器函式這個物件是是什麼時候產生的呢?是python編譯位元組碼的時候就產生了,
既然是生成器物件,那麼一定可以使用for迴圈進行遍歷,並且yield可以多次
def gen_func(): yield 1 yield 2 yield 3 yield 4
yield的特性:惰性求值, 延遲求值提供了可能
斐波那契數列的經典舉例:
def fib(index): if index <= 2: return 1 else: return fib(index-1) + fib(index-2) print(fib(10))
這樣雖然可以做出來,但是沒有具體的過程,那改進一下
def fib2(index): relist = [] n,a,b= 0,0,1 while n<index: relist.append(b) a, b = b, a+b n += 1 return relist
假如說現在index很大,上億,那記憶體就有可能不夠了。
def fib2(index): n,a,b = 0,0,1 while n<index: yield b a, b = b, a+b n += 1
改成這樣,內部沒有維護一個列表,自然而然就不會消耗記憶體的
當然這樣可以直接進行for迴圈了
那生成器的原理是什麼呢?適用於什麼場景呢?如何區別於函式呢?
def foo(): bar() def bar(): global frame frame = inspect.currentframe() # python.exe會用一個叫做 PyEval_EvalFramEx(c函式)去執行foo函式, 首先會建立一個棧幀(stack frame)
python一切皆物件,棧幀物件, 位元組碼物件
當foo呼叫子函式 bar, 又會建立一個棧幀
所有的棧幀都是分配在堆記憶體上,這就決定了棧幀可以獨立於呼叫者存在
利用生成器表示式讀取大檔案:
有人可能講了,for line in f.open()
但是如果只有一行呢?
f.read(4096) # 先讀4096個字元 f.read(4096) # 自動再次讀取4096個字元
# 500G, 特殊 一行 def myreadlines(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) if not chunk: # 說明已經讀到了檔案結尾 yield buf break buf += chunk with open("input.txt") as f: for line in myreadlines(f, "{|}"): print(line)