迭代器+生成器+函式遞迴+三元表示式+生成式+二分法
阿新 • • 發佈:2021-07-02
內容概要
- 迭代器
- 生成器
- 函式遞迴
- 三元表示式
- 生成式
- 二分法
內容詳細
-
迭代器
# 1.什麼是迭代器 # 迭代器指的是迭代取值的工具,迭代是一個重複的過程, # 每次重複都是基於上一次的結果而繼續的,單純的重複並不是迭代 # 2.為何要有迭代器 # 迭代器是用來迭代取值的工具,而涉及到把多個值迴圈取出來的型別 # 有:列表、字串、元組、集合、字典、檔案 l = ['ycc','xixi','haha'] count = 0 while count < len(l): print(l[count]) count += 1 # 上述迭代取值的方式只適用於有索引的資料型別:列表、字串、元組 # 為了解決基於索引迭代取值的侷限性,python必須提供一種能夠不依賴於索引的取值方式,這就是迭代器 # 3.如何用迭代器 # 可迭代物件:但凡內建有__iter__方法的都稱為可迭代的物件 # s1 = 'abc' # s1_iterator = s1.__iter__() # l = [] # l_iterator = l.__iter__() # set1 = {1,2,3} # set1_iterator = set1.__iter__() # dic = {'a':1,'b':2,'c':3} # dic_iterator = dic.__iter__() # tup = (1,2,3) # tup_iterator = tup.__iter__() # with open('a.txt','w') as f: # f.__iter__() # pass # 4.例: s1 = 'abc' s1_iterator = s1.__iter__() # 等價於 iter(s1) print(s1_iterator.__next()) # a print(s1_iterator.__next()) # b print(s1_iterator.__next()) # c print(s1_iterator.__next()) # error:StopIteration # 只有三個值取完就報錯 # 可迭代物件與迭代器物件詳解: 1.可迭代物件(可以轉換成迭代器的物件):內建有__iter__()方法的物件 可迭代物件.__iter__() = 迭代器物件 2.迭代器物件:內建有__next__()並且內建有__iter__() 迭代器物件.__next__() = 得到的下一個值 迭代器物件.__iter__() = 得到迭代器本身,說白了掉了跟沒調一個用 # 1. # d = {'a':1,'b':2,'c':3} # d_iterator = d.__iter__() # print(d_iterator is d_iterator.__iter__()) # True 迭代器物件 = 迭代器物件.__iter__() # 2. # for迴圈的工作原理:for迴圈可稱之為迭代器迴圈 # 1. d.__iter__()得到一個迭代器物件 # 2. 迭代器物件.__next__()得到一個返回值,然後將返回值賦給k # 3. 迴圈往復步驟2,直到丟擲異常for迴圈會捕捉異常結束 d = {'a':1,'b':2,'c':3} for k in d: print(d) d_iterator = d.__iter__() while True: try: print(next(d_iterator)) except StopIteration: break print('=============================>') d_iterator = d.__iter__() # 這裡必須再調一次迭代器功能,因為上面已經將值取完了 while True: try: print(next(d_iterator)) except StopIteration: break # 3. print(list('hello')) # ['h', 'e', 'l', 'l', 'o'] 原理同for迴圈 # 4. # 可迭代物件:字串、列表、字典、元組、集合、檔案物件 # 迭代器物件:檔案物件 # 可迭代物件只有呼叫內建方法.__iter__()才能變成迭代器物件 # 檔案物件既是可迭代物件也是迭代器物件 # with open('user.txt','w') as f: # f.__iter__() # f.__next__() # pass # 5.迭代器的優缺點總結 # 優點: # 1.為序列和非序列型別提供了一種統一的迭代取值方式。 # 2.惰性計算:迭代器物件表示的是一個數據流,可以只在需要時才去呼叫next來計算出一個值, # 就迭代器本身來說,同一時刻在記憶體中只有一個值,因而可以存放無限大的資料流,而對於其他容器型別, # 如列表,需要把所有的元素都存放於記憶體中,受記憶體大小的限制,可以存放的值的個數是有限的。 # 缺點: # 1.除非取盡,否則無法獲取迭代器的長度 # 2.只能取下一個值,不能回到開始,更像是‘一次性的’,迭代器產生後的唯一目標就是重複執行next方法直到值取盡, # 否則就會停留在某個位置,等待下一次呼叫next;若是要再次迭代同個物件, # 你只能重新呼叫iter方法去建立一個新的迭代器物件,如果有兩個或者多個迴圈使用同一個迭代器 # , 必然只會有一個迴圈能取到值
-
生成器
# 如何得到自定義的迭代器 # 在函式內一旦存在yield關鍵字,呼叫函式並不會執行函式體程式碼,會返回一個生成器物件,生成器即自定義的迭代器 def func(): print('第一次') yield 1 print('第二次') yield 2 print('第三次') yield 3 print('第四次') func() g = func() g.__iter__() # # 會觸發函式體程式碼的執行,然後遇到yield停下來,將yield後的值當作本次呼叫的結果返回 res1 = g.__next__() print(res1) res2 = g.__next__() print(res2) res3 = g.__next__() print(res3) # res4 = g.__next__() # StopIteration # ps:補充 # len('aaa') # 等同於'aaa'.__len__() # next(g) # 等同於g.__next__() # iter(可迭代物件) # 等同於 可迭代物件.__iter__() # 應用: def my_range(start,stop,step=1): while start < stop: yield start start += step g = my_range(1,5,2) while True: try: print(next(g)) except StopIteration: break # for i in my_range(1,10,2): # print(i) # ps:retrun 與 yield的區別: # 有了yield關鍵字,我們就有了一種自定義迭代器的實現方式。yield可以用於返回值, # 但不同於return,函式一遇到return就結束了,而yield可以儲存函式的執行狀態掛起函式,用來返回多次值。
-
函式遞迴
# 函式遞迴呼叫:是函式巢狀呼叫的一種特殊形式 # 具體是指:在呼叫函式的過程中,直接或間接的又呼叫到本身 # import sys 瞭解 # print(sys.getrecursionlimit()) # 1000 最多死迴圈1000次 # sys.setrecursionlimit() # 這個方法可以將限制1000次進行修改 # 一、遞迴定義 # 直接呼叫本身(死迴圈) def f1(): print('是我自己') f1() f1() # 間接呼叫本身(死迴圈) def f1(): print('===>f1') f2() def f2(): print('===>f2') f1() f1() # 一段程式碼的迴圈執行的方案有兩種 # 方案一:while、for迴圈 while True: print(11) print(22) # 方案二: 遞迴的本質就是迴圈 def f1(): print(1) print(2) f1() f1() # 二、要強調的一點是: # 遞迴呼叫不應該無限的呼叫下去,應該在滿足某種條件下結束遞迴呼叫 # 例:取小於10的數 # 方案一 :while、for迴圈 count = 0 while count < 10: print(count) count += 1 # 方案二: 遞迴 def func(count): if count > 9: return count += 1 func(count) func(0) # 三、遞迴的兩個階段 # 回溯:一層一層呼叫下去 # 遞推:滿足某種結束條件,結束遞迴呼叫,然後一層一層返回 # 例: # age(5) = age(4)+10 # age(4) = age(3)+10 # age(3) = age(2)+10 # age(2) = age(1)+10 # age = 18 def age(n): if age == 18: return return age(n) = age(n-1)+10 age() # 四、遞迴函式的應用,打印出下面列表的所有元素 l = [1,[2,[3,[4,5,[6,[7,[8,9,10]]]]]]] for x in l: # 如果是列表應該再迴圈再判斷 if type(x) is list: pass # 這裡會套無數個判斷 else: print(x) # 轉換思路用遞迴 def func(list1) for x in list1: if type(x) is list: func(x) else: print(x) func(l)
-
三元表示式
def func(x,y): if x > y: return x else: return y func() # 三元表示式 簡化函式體 # 格式:條件成立時要返回的值 if 條件 else 條件不成立時要返回的值 def func(x,y) return x if x > y else y res = func(1,3) print(res) # 3
-
生成式
# 1.列表生成式 l = ['alex_dsb','egon_dsb','lxx_dsb','jason_dsb','ycc'] # 將列表中含'dsb'的篩選數來組成一個新列表 # 方案一:for迴圈+if判斷+append new_l = [] for name in l: if name.endswith('dsb'): new_l.append(name) print(new_l) # 方案二:生成式 new_l1 = [name for name in l if name.endswith('dsb')] # 將字尾_dsb去掉 new_l2 = [name.replace('_dsb','') for name in l] # 將字尾_dsb加上 new_l3 = [name+'_dsb' for name in new_l2] # 2.字典生成式 dic = {'name':'ycc','age':27,'gender':'male'} new_dic = {k:v for k,v in dic.items() if k != 'gender'} print(new_dic) items = [('name','ycc'),('age',27),('hobbies',['play',])] new_items = {k:v for k,v in items if k != 'hobbies'} print(new_items) # 3.集合生成式 keys = ['name','age','hobbies'] new_keys = {k for k in keys} print(new_keys) # 4.生成器生成式 # g = (i for i in range(1,20) if i <18) # # 此刻g內部一個值也沒有 # # print(next(g)) # print(next(g)) # print(next(g)) # print(next(g)) # sum()的使用方法 # print(sum({1, 2, 3})) # 要放可變型別 # 將a.txt中的字元個數和算出來 # with open('user.txt','rt',encoding='utf-8') as f: # 方法一: # res = 0 # for line in f: # res += len(line) # print(res) # 方法二:生成式 # print(sum([len(line) for line in f])) # 方法三: # g = (len(line) for line in f) # 此刻內部一個值也沒有 # print(sum(g)) # 寫成一行就是: # print(sum((len(line) for line in f))) # 簡寫,可以去掉重複的括號 # print(sum(len(line) for line in f))
-
二分法
# 必須是從小到大排序的數字列表 # 如果沒有排序,用.sort()將其排序 nums = [-3,5,26,35,55,66,77,88,99,100] find_num = 88 def binary_search(find_num,l): if find_num not in l: print('值不存在') return mid_index = len(nums) // 2 mid_nums = l[mid_index] if find_num > mid_num: l = l[mid_index+1:] binary_search(find_num,l) elif find_num < mid_num: l = l[:mid_index] binary_search(find_num,l) else: print('find it') binary_search(find_num,nums)