日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

五分鐘帶你搞懂python 迭代器與生成器

瀏覽:33日期:2022-07-12 18:17:15

前言

大家周末好,今天給大家帶來的是Python當中生成器和迭代器的使用。

我當初第一次學到迭代器和生成器的時候,并沒有太在意,只是覺得這是一種新的獲取數據的方法。對于獲取數據的方法而言,我們會一種就足夠了。但是在我后來Python的使用以及TensorFlow等學習使用當中,我發現很多地方都用到了迭代器和生成器,或者是直接使用,或者是借鑒了思路。今天就讓我們仔細來看看,它們到底是怎么回事。

迭代器

我們先從迭代器開始入手,迭代器并不是Python獨有的概念,在C++和Java當中都有iterator的概念,兩者的使用也都差不多。迭代器主要解決了一個問題,在一個復雜場景下,獲取數據怎么盡可能簡便。

我們來假設一個場景,假設我們從某個數據源獲取了一批數據。然后我們需要調用前一萬條生成一個結果,得到結果之后,我們要將剩下的數據交給另一個調用方去處理。這個過程看起來非常平常,但是隱藏了兩個問題,第一個問題是如果我們能保證第一次處理的時候,每次都是使用一萬條還好說,如果我們使用的條數是一個動態的值呢?顯然,我們需要一個變量來記錄我們究竟用了多少條數據,和這批數據的狀態。其次,如果這個數據量很大會存在一個數據傳輸的問題。我們每次都要將一大批數據傳來傳去,顯然會消耗很多資源。

還有一個場景是如果我們開發的是一個比較復雜的數據結構,比如一棵多叉樹,下游想要遍歷它的時候,必須要了解它的實現原理才行。這顯然也不太友好。

迭代器的出現正是針對以上這些問題,它的含義也很簡單,有點像是我們遍歷鏈表的時候用到的cur的指針。永遠指向當前的位置,永遠知道下一個位置在哪里。

容器迭代器

我們先從簡單的元素迭代器開始了解它的用途,我們都知道Python當中經典的幾個容器:list, tuple和dict。它們都是一個可迭代對象,我們可以直接使用關鍵字iter獲取一個對應的迭代器。

我們來看一個例子:

arr = [1, 3, 4, 5, 9]it = iter(arr)print(next(it))print(next(it))

這是一個非常經典的例子,我們首先定義了一個數組,然后通過iter關鍵字獲取了一個讀取它的迭代器。有了迭代器之后我們可以通過next關鍵字獲取迭代器當中的下一個元素,我們一共調用了兩次next,第一次輸出的結果是1,第二次的結果是3。和我們剛才說的一樣,我們每一次調用,它會自動往后移動一格,獲取后面一位的數據。

這里有一點需要注意,因為我們創建的數組當中一共只有5個元素,如果我們調用it的次數超過5次,那么會引發超界,Python的解釋器會拋出StopIterat****ion的error。

除了使用next,我們也可以使用for循環來迭代它:

for i in it: print(i)

這種用法就和我們用for循環遍歷元素是一樣的。

自定義迭代器

官方的迭代器的用法就這么多,這也不是它的主要用法,它最主要的用法是我們自己創建迭代器。和之前介紹Python自定義排序的時候的思路一樣,我們為類添加上__iter__方法和__next__方法即可。

其中__iter__方法用來初始化并返回迭代器,關于它的解釋比較復雜。在Python當中迭代有兩個概念一個是iterable,一個是iterator。協議規定iteratble的__iter__方法會返回一個iterator。而iterator本身也是一個iterable對象,自然也需要實現__iter__方法。

我知道這么說可能聽不太明白,我舉個例子,比如說員工和老板,員工沒有審批權限,只能轉達給老板。我們把員工比喻成iterable對象,老板比喻成iterator。

員工面臨一個問題的時候沒有權限處理,只能找來老板決定。也就是最終決定的是老板,但如果是老板自己發現的問題,他完全可以自己就解決了,不需要再去找其他人。所以說我們用iter調用iterable對象的__iter__的時候,會得到一個iterator,也就是調用員工返回老板,然后通過調用iterator的__next__來進行迭代。

到這里也就清楚了,只有iterator有__next__方法,而iterable沒有,并且__iter__返回的是一個iterator。然而我們定義的已經是iterator了,它同時也是一個iterable對象,所以調用__iter__時只需要返回self就好了。__next__方法很簡單,對應迭代器的next方法,用來返回下一個迭代的元素。

我們來看一個例子:

class PowTwo: '''Class to implement an iterator of powers of two''' def __init__(self, max = 0): self.max = max def __iter__(self): self.n = 0 return self def __next__(self): if self.n <= self.max: result = 2 ** self.n self.n += 1 return result else: raise StopIteration

這是一個簡單的生成2的冪的迭代器,我們在__iter__里為self.n初始化為0,然后返回自身。在__next__里判斷有沒有迭代結束,如果結束的話拋出一個異常。

我們來看使用它的例子:

>>> a = PowTwo(4)>>> i = iter(a)>>> next(i)1>>> next(i)2>>> next(i)4>>> next(i)8>>> next(i)16>>> next(i)Traceback (most recent call last):...StopIteration

我們也可以用for循環來迭代它:

>>> for i in PowTwo(5):... print(i)... 12481632

迭代器除了可以迭代一個容器或者是像上面這樣自定義迭代方法之外,還可以用來迭代生成器。下面就讓我們一起來看下生成器的概念。

生成器

生成器的概念和迭代器相輔相成,迭代器是生成一個遍歷數據的迭代工具,而生成器則是數據生成工具。

舉個很簡單的例子,比如說斐波那契數列我們都知道,從第三個數開始等于前面兩個數的和。比如我們想獲取100萬個斐波那契數列,按照傳統的方法我們需要開辟一個長度是一百萬的數組,然后按照斐波那契數列的定義一個一個地計算。顯然這樣會消耗大量的空間,有沒有辦法我們和迭代器那樣構建一個生成數據的方法,我們每次調用獲取下一個結果呢?這樣我們要多少數據就調用多少次就可以了,從根本上解決了存儲的問題。

下面我們來看怎么定義一個生成器。

括號創建法

最簡單的方法真的很簡單,和我們創建list基本上一模一樣。

在Python當中,我們經常這樣初始化一個數組:

arr = [i * 3for i in range(10)]

也就是說我們把循環放在list的定義當中,這樣Python會自動執行里面的循環,然后將所有循環的結果進行二次計算后寫入到list當中去。我們稍微變形一下,就得到了一個最簡單的生成器。

g = (i * 3for i in range(10))print(next(g))

看清楚了嗎,其實和list沒什么差別,只是我們將最外層的括號從[]換成了()。

這種方法大家應該都能看懂,但是可能會有一個疑惑。我們這樣做的意義是什么呢?這樣和上面用[]定義有什么區別呢?

其實是有區別的,如果沒有區別,那么我們用生成器也就沒有意義了。它的區別也就是生成器的意義,簡單來說,我們前文中已經說過了當定義一個list的時候,Python會自動將for循環執行一遍,然后將結果寫入進list當中。但是生成器不會,雖然我們也用到了for循環,但是它只是起到了限制個數的作用,在執行完這一步之后,Python并不會將for循環執行結束。只有我們每次調用next,才會觸發它進行一次循環。

不相信的同學可以試試,看看運行一下下面兩個語句的區別:

g = (i for i in range(1000000000))g = [i for i in range(1000000000)]

如果奇怪的事情發生了,不妨再回到文章來思考一下。

函數創建法

上面介紹的方法雖然簡單,但是不太實用,因為很多時候我們想要的數據構造方法會比較復雜,很難用這種形式展現出來。

所以Python當中還為我們提供了一種構造生成器的方法,相比起來要稍微復雜一點點,但是也很好用。我們來看一個例子:

def gtr(n): for i in range(n): yield i

從代碼上來看,我們好像定義了一個函數,某種程度上可以這么理解,但是它返回的結果并不是一個值,而是一個生成器[2]。

如果你真的去試了,你會得到一個generator類型的實例,這也是Python自帶的生成器的實例。

再仔細觀察一下,你會發現這個函數當中的關鍵字和一般的不太一樣,它沒有使用return,而是使用了yield。yield和return在很大程度上很接近,但是又有些不同。

相同點是當我們執行到yield時,和return一樣會將yield之后的內容返回給調用方。比如上面代碼當中寫到yield i,那么我們運行next的時候就會獲取到這個i。

不同的地方是,當我們下一次再次執行的時候,會繼續從上次yield處開始往下執行。有些類似于遞歸的時候,底層的遞歸執行結束回到上層的情況。因此如果我們要獲取多個值,需要在生成器當中使用循環。舉個例子:

def test(): n = 0 whileTrue: if n < 3: yield n n += 1 else: yield10 if __name__ == ’__main__’: t = test() for i in range(10): print(next(t))

我們如果執行上面這段代碼,前三個數是0,1和2,從第四個數開始一直是10。如果你能看懂這個例子,一定能明白yield的含義。

yield from

接下來要介紹的yield from和yield用法差不多,也是從生成器返回一個結果,并且下次執行的時候從返回的位置開始繼續執行。

但是它有一點和yield不同,我們來看一個經典的例子。

def g1(): yield range(5)def g2(): yieldfrom range(5)it1 = g1()it2 = g2()for x in it1: print(x)for x in it2: print(x)

這兩者打印出來的結果是一樣的,但是邏輯完全不同。在第一個生成器g1當中,直接通過yield返回了一個迭代器。也就是說我們for循環執行的其實是range(5),而第二個生成器g2則通過yield from獲取了range(5)這個迭代器當中的值進行的返回。

也就是說yield from可以返回一個迭代器或者是生成器執行next之后的結果。

最后,我們來看一個yield from使用的一個經典場景:二叉樹的遍歷:

class Node: def __init__(self, key): self.key = key self.lchild = None self.rchild = None self.iterated = False self.father = None def iterate(self): if self.lchild isnotNone: yieldfrom self.lchild.iterate() yield self.key if self.rchild isnotNone: yieldfrom self.rchild.iterate()

在這個代碼當中我們定義了二叉樹當中的一個節點,以及它對應的迭代方法。由于我們用到了yield來返回結果,所以iterate方法本質是一個生成器。再來看iterate方法內部,我們通過yield from調用了iterate,所以我們在執行的時候,它會自動繼續解析node.lchild的iterate,也就是說我們通過yield from實現了遞歸。

當我們建好樹之后,可以直接使用root.iterate來遍歷整棵樹。

class Tree: def __init__(self): #建樹過程 self.root = Node(4) self.root.lchild = Node(3) self.root.lchild.father = self.root self.root.rchild = Node(5) self.root.rchild.father = self.root self.root.lchild.lchild = Node(1) self.root.lchild.lchild.father = self.root.lchild self.root.rchild.rchild = Node(7) self.root.rchild.rchild.father = self.root.rchild def iterate(self): yieldfrom self.root.iterate()

通過yield from,我們可以很輕松地利用遞歸的思路來實現樹上的生成器。從而可以很方便地以生成器的思路來遍歷樹上所有的元素。

到這里,關于Python當中迭代器和生成器的知識就算是講完了,這兩者的概念有些接近,但是又不完全一樣,很多初學者容易搞混淆。

其實可以這么理解,迭代器和生成器遍歷元素的方式是一樣的,都是通過調用next來獲取下一個元素。我們通過yield創建函數,返回的結果其實就是生成器生成的數據的迭代器。也就是說迭代器只是迭代和獲取數據的,但是并不能無中生有地創造數據。而生成器的主要作用是創造數據,它生成出來的數據是以迭代器的形式返回的。

舉個例子,你開了一個奶茶店,通過奶茶店每個月可以在銀行賬戶里獲得一筆收入。迭代器就是這個賬戶,通過它你可以獲得一筆一筆的收入。而奶茶店則是一個生成器,它產出數據,但是是以迭代器的形式返回給你的,也就是以銀行賬戶的方式給你收入。我們拿到銀行卡并不知道它里面的錢是怎么賺來的,只能看到錢,也就是說我們并不知道迭代器背后數據的邏輯。但是生成器我們是清楚的,因為錢(生產邏輯)是我們親自賺來的。

以上就是五分鐘帶你搞懂python 迭代器與生成器的詳細內容,更多關于python 迭代器與生成器的資料請關注好吧啦網其它相關文章!

標簽: Python 編程
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
一区免费视频| 国产精品多人| 91亚洲国产高清| 福利精品在线| 欧美国产偷国产精品三区| 高清在线一区| 国产美女视频一区二区| 欧美日韩一区二区三区不卡视频| 亚洲精品婷婷| 日韩精品免费观看视频| 91在线成人| 精品亚洲a∨一区二区三区18| 精品视频一区二区三区四区五区| 精品一区二区男人吃奶| 免费高潮视频95在线观看网站| 欧美午夜精彩| 国产精品成人国产| 国产h片在线观看| 国产一区日韩一区| 国产免费成人| 日韩精品三级| 免费一级欧美在线观看视频| 亚洲一区二区成人| 日本成人一区二区| 国产精品免费99久久久| 狠狠久久伊人| 亚洲91精品| 久久国产精品99国产| 91精品国产自产观看在线| 精品亚洲免a| 欧美日韩激情| 91欧美极品| av综合电影网站| 国产一区日韩一区| 中文字幕一区二区三区四区久久 | 久久久久国产一区二区| 午夜影院欧美| 午夜性色一区二区三区免费视频| 久久午夜影院| 日韩亚洲精品在线| 国产精品久久免费视频| 久久激情中文| 日韩和欧美的一区| 亚洲精品在线影院| 亚洲网址在线观看| 加勒比视频一区| 国产视频亚洲| 免费观看亚洲天堂| 99免费精品| 欧美视频二区| 亚洲成人免费| 免费在线视频一区| 91视频精品| 日韩不卡手机在线v区| 伊人久久高清| 欧美久久亚洲| 亚洲激情偷拍| 国产精品久久久久久久久久10秀| 美女精品在线观看| 色一区二区三区| 日韩1区2区3区| 日韩高清不卡| 国产精品九九| 亚洲精品在线观看91| 国产高清视频一区二区| 国产一区91| 91视频一区| 欧美另类中文字幕| 欧美综合二区| 欧美亚洲国产一区| 国产精品jk白丝蜜臀av小说| 国产在线一区不卡| 91精品国产经典在线观看| 欧美日韩视频免费观看| 日本成人在线不卡视频| 激情综合自拍| 久久免费精品| 无码日韩精品一区二区免费| 国产精品17p| 久久福利精品| 欧美成a人国产精品高清乱码在线观看片在线观看久 | 99久久久国产精品美女| 亚洲精品福利| 香蕉精品久久| 国产66精品| 国产亚洲高清在线观看| 国产亚洲网站| 在线日韩一区| 日韩av在线中文字幕| 青草综合视频| 亚洲v天堂v手机在线| 午夜av一区| 日本久久成人网| 另类欧美日韩国产在线| 麻豆亚洲精品| 好看不卡的中文字幕| 亚洲一区资源| 久久久久亚洲精品中文字幕| 日韩精品三级| 亚洲毛片在线免费| 丝袜a∨在线一区二区三区不卡| 国产麻豆久久| 国产精品国产一区| 久久精品国产亚洲一区二区三区| 欧美精品三级在线| 日本免费新一区视频| 亚洲精品乱码久久久久久蜜桃麻豆| 欧美日韩激情| 国产精品婷婷| 成人国产精品一区二区免费麻豆| 亚洲一区二区三区在线免费| 国产精品香蕉| 欧美日本久久| 在线看片国产福利你懂的| 久久久水蜜桃av免费网站| 麻豆91精品| 国产毛片一区二区三区 | 99精品在线| 日韩av一区二区三区四区| 一本色道精品久久一区二区三区| 国产福利电影在线播放| 国产精品色在线网站| 亚洲一区网站| 欧美午夜不卡| 午夜在线观看免费一区| 美女网站一区| 国产在线看片免费视频在线观看| 久久精品资源| 美女av一区| 国产日韩一区二区三区在线| 日本午夜精品久久久久| 日本麻豆一区二区三区视频| 91免费精品国偷自产在线在线| 日韩精品视频在线看| 欧美亚洲二区| 国产精品jk白丝蜜臀av小说| 国产麻豆精品久久| 一区二区不卡| 色综合视频一区二区三区日韩 | 国产综合婷婷| 狠狠久久婷婷| 国模 一区 二区 三区| av亚洲免费| 国产精品7m凸凹视频分类| 亚洲欧美日韩高清在线| 性欧美精品高清| 亚洲人www| 欧美日韩一区二区三区在线电影| 国产精品调教视频| 免费中文字幕日韩欧美| 亚洲天堂久久| 欧美freesex黑人又粗又大| 日韩免费久久| 99久久夜色精品国产亚洲狼 | 捆绑调教日本一区二区三区| 在线观看精品| 在线亚洲观看| 一区二区三区网站| 日韩av中文字幕一区| 国产精品久久久亚洲一区| 欧美激情综合| 国产91在线精品| 久久久久久亚洲精品美女| 欧美久久香蕉| 久久av导航| 老鸭窝毛片一区二区三区| 亚洲精品乱码| 国产精品一区二区av日韩在线 | 亚洲欧美久久久| 亚洲欧洲专区| 欧美黑人巨大videos精品| 激情国产在线| 亚洲激情黄色| 91成人在线| 开心激情综合| 国产一区二区中文| 日韩一区二区三区四区五区| 91p九色成人| 91一区二区| 亚洲欧洲午夜| 国产日韩高清一区二区三区在线 | 99国内精品| 日韩成人一级| 国产高清不卡| 美国三级日本三级久久99 | 91久久中文| 国产欧美久久一区二区三区| 国语对白精品一区二区| 丝袜亚洲另类欧美| 国产精品成人国产| 亚洲成人三区| 国产私拍福利精品视频二区| 青青久久av| 麻豆国产欧美日韩综合精品二区| 日韩一区二区三区免费播放| 丝袜a∨在线一区二区三区不卡| 老司机精品视频网| 午夜久久中文| 日本va欧美va精品发布| 激情久久久久久久|