您好,登錄后才能下訂單哦!
這篇“python中的迭代器和生成器怎么用”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“python中的迭代器和生成器怎么用”文章吧。
迭代(iterate)意味著重復(fù),就像 for 循環(huán)迭代序列和字典那樣,但實際上也可使用 for 循環(huán)迭代其他對象:實現(xiàn)了方法 __iter__ 的對象(迭代器協(xié)議的基礎(chǔ))。
__iter__方法返回一個迭代器,它是包含方法 __next__ 的對象,調(diào)用時可不提供任何參數(shù);
當(dāng)你調(diào)用 __next__ 時,迭代器應(yīng)返回其下一個值;如果沒有可供返回的值,應(yīng)引發(fā) StopIteration 異常;
也可使用內(nèi)置函數(shù) next(),此種情況下,next(it) 與 it.__next()__ 等效。
至于為什么不用列表?因為在很多情況下,使用列表都有點太浪費了。例如,如果你有一個可逐個計算值的函數(shù),你可能只想逐個地獲取值,而不是使用列表一次性獲取。這是因為如果有很多值,列表可能占用太多的內(nèi)存。
下面來看一個不能使用列表的示例,因為如果使用,這個列表的長度將是無窮大的!
# 這個“列表”為斐波那契數(shù)列,表示該數(shù)列的迭代器如下: class Fibs: def __init__(self): self.a = 0 self.b = 1 def __next__(self): self.a, self.b = self.b, self.a + self.b return self.a # 前面邏輯自定義,最后返回下一個值即可 def __iter__(self): return self # 返回迭代器本身(一個包含 __next__ 方法的對象) fibs = Fibs() for f in fibs: if f > 1000: print(f) # 1597 break # 若不中斷循環(huán),將一直循環(huán)下去 next(fibs) # 2584 next(fibs) # 4181
更正規(guī)的定義是,實現(xiàn)了方法 __iter__ 的對象是 可迭代的,再實現(xiàn)了方法 __next__ 的對象是 迭代器。
通過對可迭代對象調(diào)用內(nèi)置函數(shù) iter(),可以獲得一個迭代器。還可使用它從函數(shù)或其他可調(diào)用對象創(chuàng)建可迭代對象。
不過,可迭代對象在轉(zhuǎn)化為迭代器后,會丟失?些屬性(如 __getitem__() ),但同時也會增加?些屬性(如 __next__() )。
另外,迭代器一般都是?次性的,當(dāng)?shù)^?輪后,再次迭代將獲取不到元素;而可迭代對象可以重復(fù)使用。
it = iter([1, 2, 3]) # list 是可迭代對象哦 next(it) # 1 next(it) # 2 next(it) # 3 next(it) # StopIretation; 普通的可迭代對象是可復(fù)用的,而迭代器是一次性的,回不了頭的 it = iter("ABCD") # string 也是可迭代對象 for i in it: print(i, end=" ") # A B C D for i in it: print(i, end=" ") # ?輸出
查看對象是否實現(xiàn)了魔法方法 _iter_ 的四種方法:
# ?法1:dir()查看__iter__,詳情請自己嘗試 dir(2) # 沒有 dir("abc") # 有 __iter__() # ?法2:isinstance()判斷 import collections isinstance(2, collections.Iterable) # False isinstance("abc", collections.Iterable) # True # ?法3:hasattr()判斷 hasattr(2,"__iter__") # False hasattr("abc","__iter__") # True # ?法4:?iter()查看是否報錯 iter(2) # 報錯:'int' object is not iterable iter("abc") # <str_iterator at 0x1e2396d8f28>
在可以使用序列的情況下,大多也可以使用迭代器或可迭代對象(諸如索引和切片等操作除外)。迭代器因為缺少 __getitem__ ,因此不能使?普通的切?語法,暫未深究。
# 使用構(gòu)造函數(shù) list() 顯示的將迭代器轉(zhuǎn)換為列表 class TestIterator: value = 0 def __next__(self): self.value += 1 if self.value > 10: raise StopIteration return self.value def __iter__(self): return self ti = TestIterator() ti2 = list(ti) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] for i in ti2: print(i, end=" ") # 1 2 3 4 5 6 7 8 9 10 print('the second:')
生成器,也被稱為簡單生成器(simple generator),生成器自動創(chuàng)建了 iter() 和 next() 方法,是一種使用普通函數(shù)語法定義的迭代器
。與函數(shù)的主要的形式差別就在于,它的函數(shù)體中有一句 yield 語句。
每次執(zhí)行到 yield 處時,生成并返回一個值后,函數(shù)都將暫時停止執(zhí)行,等待下一輪迭代調(diào)用,如此往復(fù),直到迭代完。數(shù)據(jù)量大時,生成器能夠極大地節(jié)省內(nèi)存空間。下面還是通過斐波納契數(shù)列來看看:
# 斐波納契數(shù)列的生成器實現(xiàn): 返回數(shù)列的前 n 項 def fibs(n): a, b = 0, 1 for _ in range(n): yield a # 返回的是一個生成器 a, b = b, b+a f = fibs(5) print(f) # <generator object fibs at 0x05BB20B0> print(list(f)) # [0, 1, 1, 2, 3]; 此處生成器 f 已經(jīng)被迭代過一次了 for i in f: print(i, end=" ") # ?輸出; for循環(huán)會?動捕捉到 StopIteration 異常并停?調(diào)? next() print(next(f)) # StopIteration
與 return 的區(qū)別:生成器不是像 return 一樣返回一個值,而是可以生成多個值,每次返回一個;return 返回的話,這個函數(shù)就結(jié)束了。
將列表生成式的 [] 改成 () 之后,數(shù)據(jù)結(jié)構(gòu)將從列表變?yōu)樯善鳎皇窃M。如果要包裝可迭代對象(可能生成大量的值)時,若使用列表推導(dǎo)將立即實例化一個列表,從而喪失迭代的優(yōu)勢;但如果使用生成器推導(dǎo)的話,每迭代一次就生成一個值,沒必要一次性生成全部值,這樣就好的多了。而且,可以直接在既有的圓括號內(nèi)(如在函數(shù)調(diào)用中)使用生成器推導(dǎo)時,無需再添加一對圓括號。
L = [x*x for x in range(10)] # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] g = (x*x for x in range(10)) # <generator object <genexpr> at 0x052AF8F0> print(next(g)) # 0 sum(i ** 2 for i in range(10)) # 285
創(chuàng)建一個將兩層嵌套列表展開的函數(shù):
nested = [[1, 2], [3, 4], [5], 6] def flatten(nested): try: for sub in nested: for ele in sub: yield ele except TypeError: yield sub f = flatten(nested) next(f) # 1 # print(list(f)) # [2, 3, 4, 5, 6] for i in f3: print(i) # 2 3 4 5 6
創(chuàng)建一個將任意層嵌套列表展開的函數(shù):
對一層列表進(jìn)行遍歷,遍歷下層列表的時候,先對一層遍歷出來的元素再調(diào)用一次 flatten 函數(shù),這時,如果是不可再迭代的對象的話,就會報 TypeError 錯誤,捕捉到之后,yeild 返回,繼續(xù)下一個;如果是可迭代的話,就遞歸下去;
def flatten(nested): try: for sub in nested: for ele in flatten(sub): yield ele except TypeError: yield nested nested = [[[1], 2], 3, 4, [5, [6, 7]], 8] print(list(flatten(nested)))
不過,上面要注意的是:前面也提到了,字符串對象也是可迭代的,而且一般我們也不會將它拆開。更重要的是,字符串的第一個元素是一個長度為 1 的字符串,而長度為 1 的字符串的第一個元素是字符串本身。
s = 'ABCD' s2 = s[0] # 'A' s2[0] # 'A'
這樣子會造成無窮遞歸的。所以還需要檢查一下對象是否類似于字符串:
def flatten(nested): try: if isinstance(nested, str): raise TypeError for sub in nested: for ele in flatten(sub): yield ele except TypeError: yield nested nested = [[[1], '23'], 3, '43', [5, [6, '73']], 8] print(list(flatten(nested))) # [1, '23', 3, '43', 5, 6, '73', 8]
不過,它有兩個 yield 唉,這認(rèn)哪個來著???pass
def flatten(nested): try: for sublist in nested: for element in flatten(sublist): print("element:", element) yield element except TypeError: print("nested :", nested) yield nested print(list(flatten([[1, 2], [3, 4], [5], 6])))
輸出:
nested : 1
element: 1
nested : 2
element: 2
nested : 3
element: 3
nested : 4
element: 4
nested : 5
element: 5
nested : 6
element: 6
[1, 2, 3, 4, 5, 6]
以上就是關(guān)于“python中的迭代器和生成器怎么用”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。