第八章:Python高階程式設計-迭代器和生成器
阿新 • • 發佈:2020-08-16
第八章:Python高階程式設計-迭代器和生成器
Python3高階核心技術97講 筆記
目錄
- 第八章:Python高階程式設計-迭代器和生成器
- 8.1 Python中的迭代協議
- 8.2 什麼是迭代器和可迭代物件
- 8.3 生成器函式的使用
- 8.4 Python是如何實現生成器的?
- 8.5 生成器在UserList中的應用
- 8.6 生成器如何讀取大檔案
8.1 Python中的迭代協議
""" 什麼是迭代協議 迭代器是什麼? 迭代器是訪問集合內元素的一種方式, 一般用來遍歷資料 迭代器和以下標的訪問方式不一樣, 迭代器是不能返回的, 迭代器提供了一種惰性方式資料的方式 [] list , __iter__ __next__ """ class Iterable(metaclass=ABCMeta): __slots__ = () @abstractmethod def __iter__(self): while False: yield None @classmethod def __subclasshook__(cls, C): if cls is Iterable: return _check_methods(C, "__iter__") return NotImplemented class Iterator(Iterable): __slots__ = () @abstractmethod def __next__(self): 'Return the next item from the iterator. When exhausted, raise StopIteration' raise StopIteration def __iter__(self): return self @classmethod def __subclasshook__(cls, C): if cls is Iterator: return _check_methods(C, '__iter__', '__next__') return NotImplemented
8.2 什麼是迭代器和可迭代物件
from collections.abc import Iterator class Company(object): def __init__(self, employee_list): self.employee = employee_list def __iter__(self): return MyIterator(self.employee) # def __getitem__(self, item): # return self.employee[item] class MyIterator(Iterator): def __init__(self, employee_list): self.iter_list = employee_list self.index = 0 def __next__(self): #真正返回迭代值的邏輯 try: word = self.iter_list[self.index] except IndexError: raise StopIteration self.index += 1 return word if __name__ == "__main__": company = Company(["tom", "bob", "jane"]) my_itor = iter(company) # while True: # try: # print (next(my_itor)) # except StopIteration: # pass # next(my_itor) for item in company: # 執行了iter(company) print (item)
8.3 生成器函式的使用
# 生成器函式,函式裡只要有yield關鍵字 # 惰性求值,延遲求值提供了可能 def gen_func(): # 返回的是一個生成器物件,在Python編譯位元組碼是產生 yield 1 yield 2 yield 3 def fib(index): if index <= 2: return 1 else: return fib(index-1) + fib(index-2) 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 def gen_fib(index): n,a,b = 0,0,1 while n<index: yield b a,b = b, a+b n += 1 for data in gen_fib(10): print (data) # print (gen_fib(10)) # 斐波拉契 0 1 1 2 3 5 8 #惰性求值, 延遲求值提供了可能 def func(): return 1 if __name__ == "__main__": #生成器物件, python編譯位元組碼的時候就產生了, gen = gen_func() for value in gen: print (value) # re = func() # pass
8.4 Python是如何實現生成器的?
#1.python中函式的工作原理
"""
"""
import inspect
frame = None
def foo():
bar()
def bar():
global frame
frame = inspect.currentframe()
#python.exe會用一個叫做 PyEval_EvalFramEx(c函式)去執行foo函式, 首先會建立一個棧幀(stack frame)
"""
python一切皆物件,棧幀物件, 位元組碼物件
當foo呼叫子函式 bar, 又會建立一個棧幀
所有的棧幀都是分配在堆記憶體(不會立即釋放)上,這就決定了棧幀可以獨立於呼叫者存在
"""
# import dis
# print(dis.dis(foo))
foo()
print(frame.f_code.co_name)
caller_frame = frame.f_back
print(caller_frame.f_code.co_name)
def gen_func():
yield 1
name = "bobby"
yield 2
age = 30
return "imooc"
import dis
gen = gen_func()
print (dis.dis(gen))
print(gen.gi_frame.f_lasti)
print(gen.gi_frame.f_locals)
next(gen)
print(gen.gi_frame.f_lasti)
print(gen.gi_frame.f_locals)
next(gen)
print(gen.gi_frame.f_lasti)
print(gen.gi_frame.f_locals)
8.5 生成器在UserList中的應用
class company:
def __getitem__(self, item):
pass
from collections import UserList # 不要用繼承list,因為是c寫的
def __iter__(self):
i = 0
try:
while True:
v = self[i]
yield v
i += 1
except IndexError:
return
8.6 生成器如何讀取大檔案
#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)