第13天-迭代器和生成器
迭代器
迭代就是重複的一個過程,但是不是單純的重複,每一次的重複都是基於上一次的結果產生的。不過只記住迭代他就是重複的執行過程就是了。
#單純的重複不是迭代,例如: count = 0 while count < 3: print(count) count += 1 #每一次的重複都是基於上一次的結果產生的,隨著count的改變輸出不同的結果 count = 0 list = ["a", "b", "c"] while count < 3: print(list[count]) count += 1
迭代器就是迭代取數的一個工具,關鍵是我們為什麼要用迭代器呢?我們都知道python中主要的一些資料型別有整型,字串,元祖,列表,字典,集合,檔案等。對於整型而言只要一個數沒有什麼迭代器的概念,對於字串,元祖和列表我們可以通過索引去取值,但是對於字典,集合以及檔案而言,我們怎麼去像列表一樣進行取值呢?這就是迭代器引入的原因,主要就是為了不依賴與索引進行迭代取值。在python中兩個概念,一個就是可迭代物件(只要有__iter__方法的我們就稱之為可迭代物件,字串,元祖,列表,字典,集合都是可迭代物件),二是迭代器物件(不僅要有__iter__方法而且還要有__next__方法,檔案是迭代器物件),從上面的描述我們就可以看出來,迭代器物件都是可迭代的物件,但是可迭代物件卻不一定是迭代器物件。
迭代器的使用方法
dic = {'name': 'hu', 'age': 12} iter_dic = dic.__iter__() # 可迭代物件要變成迭代器才能夠進行使用 res = iter_dic.__next__() # 變成迭代器之後通過__next__方法進行迭代取值 print(res) # 對於dic迭代的值是key
當迭代器把迭代物件迴圈完畢之後會報錯
dic = {'name': 'hu', 'age': 12} count = 0 iter_dic = dic.__iter__() # 可迭代物件要變成迭代器才能夠進行使用 while count < len(dic):try: # 當最後一個迭代完了之後會報錯,因此我們需要捕捉異常 res = iter_dic.__next__() # 變成迭代器之後通過__next__方法進行迭代取值 print(res) # 對於dic迭代的值是key except StopIteration: break
從上面的程式碼我們就可以看出來,對於迭代器的使用太過於麻煩,因此python給我們專門的設計了一個迴圈for迴圈來解決這樣的事情,for迴圈可以專門的去解決可迭代物件的問題,當然迭代器物件的問題也可以,for迴圈處理的步驟1. 把可迭代物件轉換成迭代器,(迭代器的話也會執行__iter__的方法,效果是一樣的)2. 迴圈的去呼叫__next__方法進行迭代取值。3. 通過try去捕捉異常,捕捉到異常之後停止迴圈。
# 和上面的程式碼顯示的效果是一樣的 dic = {'name': 'hu', 'age': 12} for i in dic: print(i)
生成器
生成器本質上就是迭代器,只不過這個生成器是我們自己通過yield關鍵字自己建立的迭代器而已。迭代器有兩個優點 1. 可以不依賴與索引迭代取值 2.節省記憶體。而我們建立生成器為了解決最大的問題其實就是節省記憶體。
生成器建立的規則, 通過yield關鍵字進行建立迭代器。yield和return返回的是一樣的,只是yield可以中斷函式,當我需要的時候可以重新再進行建立
def foo() print(1) yield "第一" print(2) yield "第二" iter_foo = foo() print(iter_foo) next(iter_foo)
三元表示式
def max2(a, b): if a > b: return a else: return b a = 1 b = 2 c = a if a > b else b # 這一行資料就是上面那一個函式的簡潔的表達方式 print(c) c = max2(a, b) print(c)
列表生成式
l = [] for i in range(10): if i > 5: s = "egg%s" % i l.append(s) print(l) l = ["egg%s" % i for i in range(10) if i > 5] # 這一句話和前面的幾句話都是性質是一樣的,只是簡寫了而已 print(l)
生成字典表示式
d = {} s = [("hu", 12), ("zhou", 14)] for k, v in s: d[k] = v print(d) d = {k : v for k, v in s} # 這個是上面幾行程式碼的縮寫 print(d)
生成器表示式
res = (i ** 2 for i in range(5)) print(res) print(next(res)) print(next(res)) print(next(res))
練習題:
1. 編寫一個range的生成器
def my_range(start, end , step=1): while start < end: yield start start += step for i in my_range(0, 10): print(i)View Code
2. 求一個檔案中所包含的字元的個數,以及左右行中最大的個數
with open(r'04_多層裝飾器的聯絡.py', 'rt', encoding='utf-8') as f: # count = 0 # for line in f: # count += 1 # data = f.read() # print(len(data)) 649 # count = 0 # for line in f: # count += len(line) # print(count) # print(sum(len(line) for line in f)) print(max(len(line) for line in f)) # 通過生成器表示式一行寫出View Code
3. 模擬管道,實現功能:tail -f access.log | grep '404'
# 2、模擬管道,實現功能:tail -f access.log | grep '404' import time def tail(file_path): with open(file_path, 'rb') as f: f.seek(0, 2) while True: # 檢視是否有新的一行加入 line = f.readline() if line: yield line else: time.sleep(0.2) def grep(pattern, iter_tail): for line in iter_tail: line = line.decode('utf-8') if pattern in line: yield line for line in grep('404', tail('access.log')): print(line)View Code