日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

10分鐘了解Python黑魔法 Yield、Iterator、Generator

來源: 責編: 時間:2023-12-25 17:28:47 228觀看
導讀今天,我們來討論Python的yield、Iterator和generator,它們可以在許多教程中看到,但總是引起一些混淆。今天,我們來討論Python的yield、Iterator和generator,它們可以在許多教程中看到,但總是引起一些混淆。就像decorators一

今天,我們來討論Python的yield、Iterator和generator,它們可以在許多教程中看到,但總是引起一些混淆。C8x28資訊網——每日最新資訊28at.com

C8x28資訊網——每日最新資訊28at.com

今天,我們來討論Python的yield、Iterator和generator,它們可以在許多教程中看到,但總是引起一些混淆。C8x28資訊網——每日最新資訊28at.com

就像decorators一樣,這三個概念是緊密聯系在一起的。例如,如果你想知道什么是yield,你必須首先了解什么是generator。但在理解generator之前,你又必須理解iterator是什么,但在理解iterator之前,您必須要知道iterable對象是什么。他們的關系如下圖:C8x28資訊網——每日最新資訊28at.com

C8x28資訊網——每日最新資訊28at.com

Iterables 可迭代的

可迭代是指能夠通過迭代的方法遍歷的對象,比如列表、字符串、元組、字典、集合等等。簡單的例子:C8x28資訊網——每日最新資訊28at.com

mylist = [1, 2, 3]for i in mylist:    print(i)

可迭代對象如何工作?

讓我們看看Python解釋器在遇到迭代操作時如何處理迭代,例如for ... in xC8x28資訊網——每日最新資訊28at.com

  • 調用 iter(x) 函數
  • 檢查對象是否實現了 _iter__ 方法,如果實現了,則調用它以獲取迭代器;
  • 如果未實現 _iter__ 方法,但實現了_getitem__ 方法,Python將創建一個迭代器并嘗試按順序獲取元素(從索引0開始);
  • 如果兩個方法都未實現,將拋出TypeError異常,指示無法迭代該對象。

因此具有 __iter__ 方法或 __getitem__方法的對象通常稱為可迭代對象。C8x28資訊網——每日最新資訊28at.com

如何判斷一個對象是否可迭代?

  • 方法一:使用dir函數,檢查對象是否實現了__iter__ 或者 __getitem__方法。
mylist = [1, 2, 3]mylistMethod = dir(mylist)print(mylistMethod) #查看mylist的方法print('__iter__' in dir(mylist) or '__getitem__' in dir(mylist)) # True
  • 方法二:使用isinstance函數,檢查對象是否是Iterable類型。
from collections import Iterablemylist = [1, 2, 3]print(isinstance(mylist, Iterable)) # True

Iterator 迭代器

迭代器是一個包含可數數量值的對象。它可以迭代,這意味著您可以遍歷所有值。讓我們看一個迭代器示例:C8x28資訊網——每日最新資訊28at.com

for i in range(5):    print(i) # 0 1 2 3 4

像這樣,一個個打印元素的過程就叫可迭代的,這個過程也是我們日常代碼編寫中接觸最多的操作。C8x28資訊網——每日最新資訊28at.com

簡單來說,帶有next()方法的可迭代對象就是一個迭代器,或者說一個可迭代對象和一個迭代器的關系是:Python從一個可迭代對象中獲取一個迭代器。具體關系如下圖:C8x28資訊網——每日最新資訊28at.com

C8x28資訊網——每日最新資訊28at.com

所以上面提到的列表、字符串等不是迭代器。但是,您可以使用Python內置 iter()函數來獲取它們的迭代器對象。讓我們使用迭代器模式來重寫前面的例子:C8x28資訊網——每日最新資訊28at.com

mylist = [1,2,3]it = iter(mylist) # 獲取迭代器對象while True:    try:        print(next(it))    except StopIteration:        print("Stop iteration!")        break

在上面的代碼中,我們首先使用iterable對象mylist來構造迭代器it,并不斷調用迭代器上的next()函數來獲取下一個元素。如果沒有字符,迭代器將拋出 StopIteration 異常并退出循環。C8x28資訊網——每日最新資訊28at.com

Generator 生成器

Python 提供了一個生成器來創建迭代器函數。生成器是一種特殊類型的函數,它不返回單個值,而是返回一個包含一系列值的迭代器對象。在生成器函數中,使用 yield 語句而不是 return 語句。C8x28資訊網——每日最新資訊28at.com

現在我們已經知道for循環背后的機制了,但是如果數據量太大,比如for i in range(1000000),使用for循環將所有的值存儲在內存中不僅占用大量的存儲空間 但是如果我們只需要訪問前幾個元素,空間就浪費了。在這種情況下,我們可以使用 generator 。C8x28資訊網——每日最新資訊28at.com

生成器的思路是,我們不需要一次性把這個列表全部創建出來,只需要記住它的創建規則,然后在需要用到的時候,再一次次的計算和創建。我們來看一個例子:C8x28資訊網——每日最新資訊28at.com

my_generator = (x*x for x in range(10))for i in my_generator:    print(i) # 0 1 4 9 16 25 36 49 64 81

my_generator 是一個生成器,它的每一個元素都是一個生成器對象。我們可以使用 next()函數來獲取下一個元素。C8x28資訊網——每日最新資訊28at.com

Yield 產生器

簡單來說,你可以把yield當成return,但它返回的是一個生成器。記住,剛開始學習的時候不需要了解這個yield是什么,但是一定要了解它的運行機制!讓我們看一下下面的代碼片段:C8x28資訊網——每日最新資訊28at.com

def test():    print("First")    yield 1    print("Second")    yield 2    print("Third")    yield 3my_generator = test() # 創建生成器print(type(my_generator)) # <class 'generator'>

我們可以在這里看到如果一個函數使用 yield 作為返回值,那么它就變成了一個生成器函數。與普通函數不同,生成器函數被調用后,函數體中的代碼不會立即執行(執行my_generator=test()后不打印任何值),而是返回一個生成器!正如我們前面提到的:generator 是迭代器,而 yield 可以被視為 return ,不難猜測下面代碼的結果:C8x28資訊網——每日最新資訊28at.com

def test():    print("First")    yield 1    print("Second")    yield 2    print("Third")    yield 3for item in test():    print(item)# 輸出:"""First1Second2Third3"""

next 函數是如何運行的?C8x28資訊網——每日最新資訊28at.com

def test():    print("First")    yield 1    print("Second")    yield 2    print("Third")    yield 3my_generator = test() # 創建生成器a = next(my_generator) # Firstprint(a) # 1b = next(my_generator) # Secondprint(b) # c = next(my_generator) # Thirdprint(c) # 3d = next(my_generator) # StopIterationprint(d) # error

每次調用next(my_generator),只跑到yield位置就停止,下次再跑,從上次結束的位置開始!并且生成器的長度取決于在函數中定義 yield 的次數。看起來也很好理解呢。C8x28資訊網——每日最新資訊28at.com

如果理解了上面的 yield 函數示例,讓我們繼續看一個更復雜的示例,該生成器可以接受參數。C8x28資訊網——每日最新資訊28at.com

def simple_gen(a):    print('-> Started: a =', a)    b = yield a    print('-> Received: b =', b)    c = yield a + b    print('-> Received: c =', c)gen = simple_gen(14)next(gen) # -> Started: a = 14next(gen) # ?next(gen) # ?

運行結果如圖:C8x28資訊網——每日最新資訊28at.com

C8x28資訊網——每日最新資訊28at.com

發生了什么??從第一次 next(gen) 調用開始,它在 yield a 處停止,然后當您再次調用 next(gen) 時,b 實際上是 None 值,這導致了異常。C8x28資訊網——每日最新資訊28at.com

b 為什么是 None 值?因為我們在 yield a 處沒有接收到任何值,所以 b 就是 None 值。要想接收值,C8x28資訊網——每日最新資訊28at.com

要繼續,您需要使用 send() 函數:生成器發送(值)恢復執行并將值“發送”到生成器函數中。value 參數成為當前 yield 表達式的結果。send() 方法返回生成器生成的下一個值,或者如果生成器退出而沒有生成另一個值則引發 StopIteration。C8x28資訊網——每日最新資訊28at.com

怎么理解send() 函數?一個帶參數的 next(),接收參數,執行yield,然后返回值。C8x28資訊網——每日最新資訊28at.com

def simple_gen(a):    print('-> Started: a =', a)    b = yield a    print('-> Received: b =', b)    c = yield a + b    print('-> Received: c =', c)gen = simple_gen(14)next(gen) # -> Started: a = 14gen.send(15) # Received: b = 15 # send 15 to generator,并執行下一步 send包含next的yield

總結

小思考:C8x28資訊網——每日最新資訊28at.com

  • yield 和 return 的區別,你理解了么?
  • yield, generator  和 iterator 的區別和聯系,你理解了么?

本文鏈接:http://www.www897cc.com/showinfo-26-54006-0.html10分鐘了解Python黑魔法 Yield、Iterator、Generator

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: Python玩轉二維碼,炫酷!

下一篇: 除自身以外數組的乘積:三種解法及Java代碼示例

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 安平县| 塔河县| 建水县| 灵寿县| 雅江县| 龙山县| 辽宁省| 玉环县| 柘荣县| 镇宁| 宁都县| 喜德县| 都兰县| 凤阳县| 马山县| 中阳县| 育儿| 晴隆县| 集贤县| 天等县| 广州市| 皮山县| 镇巴县| 都江堰市| 合水县| 巢湖市| 慈溪市| 英超| 黑河市| 伊春市| 拉孜县| 龙南县| 南昌市| 钟山县| 淳化县| 阜新市| 蕉岭县| 衡阳县| 信丰县| 荥阳市| 清镇市|