Python中迭代器與生成器的用法
一、迭代器(foreach)
1、可迭代的對(duì)象
內(nèi)置有__iter__
方法的都叫可迭代的對(duì)象。
Python內(nèi)置str、list、tuple、dict、set、file都是可迭代對(duì)象。
x = 1.__iter__ # SyntaxError: invalid syntax # 以下都是可迭代的對(duì)象 name = 'nick'.__iter__ print(type(name)) # 'method-wrapper'>
2、迭代器對(duì)象
執(zhí)行可迭代對(duì)象的__iter__
方法,拿到的返回值就是迭代器對(duì)象。
只有字符串和列表都是依賴索引取值的,而其他的可迭代對(duì)象都是無法依賴索引取值的,只能使用迭代器對(duì)象。
- 內(nèi)置有
__iter__
方法,執(zhí)行該方法會(huì)拿到迭代器本身。 - 內(nèi)置
__next__
方法,執(zhí)行該方法會(huì)拿到迭代器對(duì)象中的一個(gè)值。
s = 'hello' iter_s = s.__iter__() print(type(iter_s)) # 'str_iterator'> iter_s為迭代器對(duì)象 while True: try: print(iter_s.__next__()) except StopIteration: break #hello
3、迭代器有兩個(gè)基本的方法:iter() 和 next()。
s = 'hello' iter_s = iter(s) # 創(chuàng)建迭代器對(duì)象 print(type(iter_s)) # iter_s為迭代器對(duì)象 while True: try: print(next(iter_s)) # 輸出迭代器的下一個(gè)元素 except StopIteration: break # hello
4、for迭代器循環(huán)
可迭代對(duì)象可以直接使用常規(guī)for語句進(jìn)行遍歷
for循環(huán)稱為迭代器循環(huán),in后必須是可迭代的對(duì)象。
#str name = 'nick' for x in name: print(x) #list for x in [None, 3, 4.5, "foo", lambda: "moo", object, object()]: print("{0} ({1})".format(x, type(x))) #dict d = { '1': 'tasty', '2': 'the best', '3 sprouts': 'evil', '4': 'pretty good' } for sKey in d: print("{0} are {1}".format(sKey, d[sKey])) #file f = open('32.txt', 'r', encoding='utf-8') for x in f: print(x) f.close()
5、實(shí)現(xiàn)迭代器(__next__和__iter__)
把一個(gè)類作為一個(gè)迭代器使用需要在類中實(shí)現(xiàn)兩個(gè)方法 __iter__() 與 __next__() 。
- __iter__() 方法返回一個(gè)特殊的迭代器對(duì)象, 這個(gè)迭代器對(duì)象實(shí)現(xiàn)了 __next__() 方法并通過 StopIteration 異常標(biāo)識(shí)迭代的完成。
- __next__() 方法會(huì)返回下一個(gè)迭代器對(duì)象。
- StopIteration 異常用于標(biāo)識(shí)迭代的完成,防止出現(xiàn)無限循環(huán)的情況,在 __next__() 方法中我們可以設(shè)置在完成指定循環(huán)次數(shù)后觸發(fā) StopIteration 異常來結(jié)束迭代。
創(chuàng)建一個(gè)返回?cái)?shù)字的迭代器,初始值為 1,逐步遞增 1,在 20 次迭代后停止執(zhí)行:
class MyNumbers: def __iter__(self): self.a = 1 return self def __next__(self): if self.a <= 20: x = self.a self.a += 1 return x else: raise StopIteration myclass = MyNumbers() myiter = iter(myclass) for x in myiter: print(x)
1、模擬range
class Range: def __init__(self, n, stop, step): self.n = n self.stop = stop self.step = step def __next__(self): if self.n >= self.stop: raise StopIteration x = self.n self.n += self.step return x def __iter__(self): return self for i in Range(1, 7, 3): print(i) #1 #4
2、斐波那契數(shù)列
class Fib: def __init__(self): self._a = 0 self._b = 1 def __iter__(self): return self def __next__(self): self._a, self._b = self._b, self._a + self._b return self._a f1 = Fib() for i in f1: if i > 100: break print('%s ' % i, end='') # 1 1 2 3 5 8 13 21 34 55 89
二、生成器
1、yield
在 Python 中,使用了 yield 的函數(shù)被稱為生成器(generator)。
跟普通函數(shù)不同的是,生成器是一個(gè)返回迭代器的函數(shù),只能用于迭代操作,更簡單點(diǎn)理解生成器就是一個(gè)迭代器。
在調(diào)用生成器運(yùn)行的過程中,每次遇到 yield 時(shí)函數(shù)會(huì)暫停并保存當(dāng)前所有的運(yùn)行信息,返回 yield 的值, 并在下一次執(zhí)行 next() 方法時(shí)從當(dāng)前位置繼續(xù)運(yùn)行。
調(diào)用一個(gè)生成器函數(shù),返回的是一個(gè)迭代器對(duì)象。
yield后面可以加多個(gè)數(shù)值(可以是任意類型),但返回的值是元組類型的。
- 提供一種自定義迭代器的方式
- yield可以暫停住函數(shù),并提供當(dāng)前的返回值
import sys def fibonacci(n): # 函數(shù) - 斐波那契 a, b, counter = 0, 1, 0 while True: if counter > n: return yield a a, b = b, a + b counter += 1 f = fibonacci(10) #f 是一個(gè)生成器 print(type(f)) # 'generator'> while True: try: print(next(f), end=" ") except StopIteration: sys.exit()
yield和return:
- 相同點(diǎn):兩者都是在函數(shù)內(nèi)部使用,都可以返回值,并且返回值沒有類型和個(gè)數(shù)的限制
- 不同點(diǎn):return只能返回一次值;yield可以返回多次值
2、自定義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)}")
復(fù)雜版本:
def range(*args, **kwargs): if not kwargs: if len(args) == 1: count = 0 while count < args[0]: yield count count += 1 if len(args) == 2: start, stop = args while start < stop: yield start start += 1 if len(args) == 3: start, stop, step = args while start < stop: yield start start += step else: step = 1 if len(args) == 1: start = args[0] if len(args) == 2: start, stop = args for k, v in kwargs.items(): if k not in ['start', 'step', 'stop']: raise ('參數(shù)名錯(cuò)誤') if k == 'start': start = v elif k == 'stop': stop = v elif k == 'step': step = v while start < stop: yield start start += step for i in range(3): print(i) # 0,1,2 for i in range(99, 101): print(i) # 99,100 for i in range(1, 10, 3): print(i) # 1,4,7 for i in range(1, step=2, stop=5): print(i) # 1,3 for i in range(1, 10, step=2): print(i) # 1,3,5,7,9
3、生成器表達(dá)式(i.for .in)
把列表推導(dǎo)式的[]換成()就是生成器表達(dá)式 。
優(yōu)點(diǎn):比起列表推導(dǎo)式,可以省內(nèi)存,一次只產(chǎn)生一個(gè)值在內(nèi)存中
t = (i for i in range(10)) print(t) # <generator object at 0x00000000026907B0> print(next(t)) # 0 print(next(t)) # 1
舉例:
with open('32.txt', 'r', encoding='utf8') as f: nums = [len(line) for line in f] # 列表推導(dǎo)式相當(dāng)于直接給你一筐蛋 print(max(nums)) # 2 with open('32.txt', 'r', encoding='utf8') as f: nums = (len(line) for line in f) # 生成器表達(dá)式相當(dāng)于給你一只老母雞。 print(max(nums)) # ValueError: I/O operation on closed file.
到此這篇關(guān)于Python迭代器與生成器的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Pycharm遠(yuǎn)程調(diào)試和MySQL數(shù)據(jù)庫授權(quán)問題
這篇文章主要介紹了Pycharm遠(yuǎn)程調(diào)試和MySQL數(shù)據(jù)庫授權(quán)問題,文章內(nèi)容介紹詳細(xì),需要的小伙伴可以參考一下,希望對(duì)你的學(xué)習(xí)或工作有所幫助2022-03-03jupyter?notebook加載和運(yùn)行.py文件方式
這篇文章主要介紹了jupyter?notebook加載和運(yùn)行.py文件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07python程序調(diào)用遠(yuǎn)程服務(wù)的步驟詳解
這篇文章主要介紹了python程序調(diào)用遠(yuǎn)程服務(wù)的步驟詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-03-03Python 通過調(diào)用接口獲取公交信息的實(shí)例
今天小編就為大家分享一篇Python 通過調(diào)用接口獲取公交信息的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-12-12Python靜態(tài)Web服務(wù)器面向?qū)ο筇幚砜蛻舳苏?qǐng)求
這篇文章主要為大家介紹了Python面向?qū)ο髮?shí)現(xiàn)靜態(tài)Web服務(wù)器處理客戶端請(qǐng)求示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06pygame學(xué)習(xí)筆記(3):運(yùn)動(dòng)速率、時(shí)間、事件、文字
這篇文章主要介紹了pygame學(xué)習(xí)筆記(3):運(yùn)動(dòng)速率、時(shí)間、事件、文字,本文講解了運(yùn)動(dòng)速率、事件、字體及字符顯示等內(nèi)容,需要的朋友可以參考下2015-04-04Python?tkinter?多選按鈕控件?Checkbutton方法
這篇文章主要介紹了Python?tkinter?多選按鈕控件?Checkbutton方法,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下2022-07-07一次搞懂hasattr()/getattr()/setattr()在Python中的應(yīng)用
在Python中,hasattr()、getattr()和setattr()是一組內(nèi)置函數(shù),本文將從入門到精通,全面介紹hasattr()、getattr()和setattr()函數(shù)的用法和相關(guān)知識(shí)點(diǎn),需要的可以了解下2023-08-08