Python之叠代器和生成器
阿新 • • 發佈:2018-04-26
OS 返回 內部 16px fun break 得到 urn b-
叠代器
一 叠代
# 叠代是一個重復的過程,每次重復即一次叠代,並且每次叠代的結果都是下一次叠代的初始值 while True: # 只是單純地重復,因而不是叠代 print(‘===>‘) li = [1, 2, 3] count = 0 while count < len(li): # 叠代 print(li[count]) count += 1
二 叠代器
#1. 叠代器 對於 字符串,列表,元組,我們可使用索引的方式叠代取出其包含的元素。但對於 字典,集合,文件等類型是
沒有索引的,若還想取出其 內部包含的元素,則需要一種 不依賴索引的叠代方式,這就是 叠代器#2. 可叠代對象
可叠代對象: 內置有 __iter__ 方法的對象。即obj.__iter__
如下: ‘hello‘.__iter__ (1,2,3).__iter__ [1,2,3].__iter__ #3. 叠代器 叠代器對象:即內置有 __iter__又內置有__next__方法的對象。 文件類型是叠代器對象 open(‘a.txt‘).__iter__() open(‘a.txt‘).__next__() #4. 註意 叠代器對象一定是可叠代對象,而可叠代對象不一定是叠代器對象
三 叠代器的使用
dic = {‘a‘: 1, ‘b‘: 2, ‘c‘: 3} iter_dic = dic.__iter__() # 得到叠代器對象,叠代器對象即有__iter__又有__next__,但是:叠代器.__iter__()得到的仍然是叠代器本身 iter_dic.__iter__() is iter_dic # True print(iter_dic.__next__()) # 等同於next(iter_dic) print(iter_dic.__next__()) # 等同於next(iter_dic) print(iter_dic.__next__()) #View Code等同於next(iter_dic) # print(iter_dic.__next__()) #拋出異常StopIteration,或者說結束標誌 # 有了叠代器,我們就可以不依賴索引叠代取值了 iter_dic = dic.__iter__() while 1: try: k = next(iter_dic) print(dic[k]) except StopIteration: break # 這麽寫太醜陋了,需要我們自己捕捉異常,控制next,python能用 for循環解決
四 for循環
# 基於for循環,我們可以完全不再依賴索引去取值了 dic = {‘a‘: 1, ‘b‘: 2, ‘c‘: 3} for k in dic: print(dic[k]) # for循環的工作原理 1:執行in後對象的dic.__iter__()方法,得到一個叠代器對象iter_dic 2: 執行next(iter_dic),將得到的值賦值給k,然後執行循環體代碼 3: 重復過程2,直到捕捉到異常StopIteration,結束循環
五 叠代器的特點
#優點: - 提供一種統一的,不依賴於索引的叠代方式 - 惰性計算,節省內存 #缺點: - 無法獲取長度(只有在next完畢才知道到底有幾個值) - 只能往後走,不能往前退
生成器
一 生成器
函數內部包含yield 被稱為生成器(generator),並且不會執行函數內部代碼
def func(): print(‘====>first‘) yield 1 print(‘====>second‘) yield 2 print(‘====>third‘) yield 3 print(‘====>end‘) g = func() print(g) # <generator object func at 0x00846BD0> # 生成器就是叠代器 print(g.__iter__) print(g.__next__)示例
# 驗證 生成器也是一個叠代器 from collections import Iterator def test(): print(‘first‘) yield 1 # 相當於1 g = test() # print(g) print(isinstance(g, Iterator)) #結果 True驗證生成器是叠代器
二 生成器與 return有何區別
#return只能一次性返回,而yield能返回多次值,可以掛起/保存函數的運行狀態
#yield 到底進行了什麽操作 1. yield把函數變成生成器 ---》因此,也是叠代器(生成器也是個叠代器) 2. 用return返回值能返回一次,而yield返回多次 3. 函數在暫停以及繼續下一次運行時的狀態是由yield保存
例子:
1. yield的 add
def add(n, i): return n + i def test(): for i in range(4): yield i g = test() for n in [1, 10]: g = (add(n, i) for i in g) ## n = 1 # #g = (add(n,i) for i in g) #[1, 2, 3, 4] # #n = 10 # #g1 = (add(n,i) for i in (add(n,i) for i in g)) # # #此處的n=10 #10,11.12.13 print(list(g)) # 結果 [20, 21, 22, 23]View Code
2.有無直接next( )
a. 有直接
# 有直接 next(e) def eater(name): print(‘{} start to eat food ‘.format(name)) food_list = [] while True: food = yield food_list print(‘{} get {},to start eat‘.format(name, food)) food_list.append(food) e = eater(‘湯姆‘) next(e) # 執行這一步!!!!!! print(e.send(‘鐵觀音‘)) print(e.send(‘西瓜‘)) print(e.send(‘燒餅‘))View Code
b. 有直接
# 無next() def init(func): # 在此添加 裝飾器,以替代 next(e) def wrapper(*args, **kwargs): res = func(*args, **kwargs) next(res) return res return wrapper @init # eater = init(eater) def eater(name): print(‘{} start to eat food ‘.format(name)) food_list = [] while True: food = yield food_list print(‘{} get {},to start eat‘.format(name, food)) food_list.append(food) e = eater(‘湯姆‘) # next(e) #不在此執行這一步 print(e.send(‘鐵觀音‘)) print(e.send(‘西瓜‘)) print(e.send(‘燒餅‘))View Code
得到同樣的結果:
‘‘‘ 湯姆 start to eat food 湯姆 get 鐵觀音,to start eat [‘鐵觀音‘] 湯姆 get 西瓜,to start eat [‘鐵觀音‘, ‘西瓜‘] 湯姆 get 燒餅,to start eat [‘鐵觀音‘, ‘西瓜‘, ‘燒餅‘] ‘‘‘
Python之叠代器和生成器