目錄python
yield的英文單詞意識就是生產,在函數中但凡出現yield關鍵字,在調用函數,就不會繼續執行函數體代碼,而是會返回一個值。編程
def func(): print(1) yield print(2) yield g = func() print(g) #輸出:# generator 生成器 <generator object func at 0x0000019C5C5BD448>
生成器 的本質就是迭代器,同時也並不只僅是迭代器,不過迭代器以外的用途實在是很少,因此咱們能夠認爲:生成器提供了很是方便的自定義迭代器的途徑。而且從python2.5+開始,[PEP 342:經過加強生成器實現協同程序的實現位生成器加入了更多的特性,這意味着,生成器還能夠完成更多的工做。這部分咱們會在稍後的部分介紹。多線程
def func(): print('from func 1') yield 'a' print('from func 2') yield 'b' g = func() print(g.__iter__()) print(g.__iter__()==g) res1 = g.__next__() print(res1) res2 = next(g) print(res2) #輸出: <generator object func at 0x00000172C20B2DC8> True from func 1 a from func 2 b
協同程序(協程)通常來講是指這樣的函數:併發
協程的特色決定了同一時刻只能有一個協同程序正在運行(忽略多線程的狀況)。得益於此,協程間能夠直接傳遞對象而不須要考慮資源鎖、或是直接喚醒其餘協程而不須要主動休眠,就像是內置了鎖的線程。在符合協程特色的應用場景,使用協程無疑比使用線程要更方便。函數
從另外一方面說,協程沒法併發其實也將它的應用場景限制在了一個很狹窄的範圍,這個特色使得協程更多的被拿來與常規函數進行比較,而不是與線程。固然,線程比協程複雜許多,功能也更強大,因此我建議你們緊緊地掌握線程便可,是否是聽了一臉懵逼,那麼就別管他了,由於併發編程你會從新學習他。所以這一節裏我也就不列舉關於協程的例子了,如下介紹的方法瞭解便可。學習
因爲Python2.5+對生成器的加強實現了協程的其餘特色,在這個版本中,生成器加入了以下方法:線程
2.1 send(value):指針
send是除next外另外一個恢復生成器的方法。Python2.5+中,yield語句變成了yield表達式,這意味着yield如今能夠有一個值,而這個值就是在生成器的send方法被調用從而恢復執行時,調用send方法的參數。code
def h(): print('--start--') first = yield 5 # 等待接收 Fighting! 值 print('1', first) second = yield 12 # 等待接收 hahaha! 值 print('2', second) yield 13 print('--end--') g = h() first = next(g) # m 獲取了yield 5 的參數值 5 # (yield 5)表達式被賦予了'Fighting!', d 獲取了yield 12 的參數值12 second = g.send('Fighting!') third = g.send('hahaha!') # (yield 12)表達式被賦予了'hahaha!' print(f'--over--') print(f"first:{first}, second:{second}, third:{third}") --start-- 1 Fighting! 2 hahaha! --over-- first:5, second:12, third:13
2.2 close()協程
這個方法用於關閉生成器。對關閉的生成器後再次調用next或send將拋出StopIteration異常。
def repeater(): n = 0 while True: n = (yield n) r = repeater() r.close() print(next(r)) # StopIteration
2.3 throw(type, value=None, traceback=None)
中斷Generator是一個很是靈活的技巧,能夠經過throw拋出一個GeneratorExit異常來終止Generator。Close()方法做用是同樣的,其實內部它是調用了throw(GeneratorExit)的。咱們看close的源代碼
def close(self): try: self.throw(GeneratorExit) except (GeneratorExit, StopIteration): pass else: raise RuntimeError("generator ignored GeneratorExit") # Other exceptions are not caught
3、自定義range()方法
def my_range(start, stop, step=1): while start < stop: yield start start += 1 g = my_range(0, 3) print(f"list(g): {list(g)}") list(g): [0, 1, 2]
4、總結
yield和return:
5、生成器表達式
t = (i for i in range(10)) print(t) print(f"next(t): {next(t)}") <generator object <genexpr> at 0x1101c4888> next(t): 0
5.1 生成器表達式和列表推導式
# 生成器表達式 with open('52.txt', 'r', encoding='utf8') as f: nums = [len(line) for line in f] print(max(nums)) #輸出: 1 # 列表推導式 with open('52.txt','r',encoding='utf8') as f: nums = (len(line) for line in f) print(max(nums)) # ValueError: I/O operation on closed file.