day14 迭代器和生成器
1.迭代器
名詞解釋
什麼是迭代:迭代是一個重複過程,但是每次重複都是基於上一次的結果而繼續的
#下列迴圈只是單純的重複,沒有意義
while True:
print(1)
#基於索引的迭代取值
l = ['a'a,'b','c']
i = 0
while i <len(l):
print(l[i])
i+=1
什麼是迭代器:
迭代取值的工具
2.為什麼要用迭代器
迭代器
1.優點:提供了一種不依賴索引的迭代取值方式
2.更節省記憶體(每次只取一個值放到記憶體中使用,下次呼叫才會取下個值)
缺點:
1.不如按照索引的取值方式靈活
2.取值一次性的,只能往後取,無法預測值的個數
3.如何用迭代器
可迭代物件:str、list、tuple\dict\set\檔案物件
但凡有__iter__方法的物件都稱之為可迭代物件
迭代器物件:檔案物件
既內建有__iter__方法又內建又__next__方法的物件都稱之為迭代器物件
(關鍵點:呼叫可迭代物件下__iter__方法,會有一個返回值,該返回值就是內建的迭代器物件)
用內建方法__next__ 可以取出迭代器的下一個值
上面iter_d拿到由d的內容產生的迭代器
但是當next取到最後一個值之後,繼續next取值,就會報錯,會丟擲異常 StopIteration
d={'k1':111,'k2':222,'k3':333}
d={1,2,3,4,5}
iter_d = d.__iter__() 一般__下滑線開頭的方法,滿足一定條件時自動觸發,最好不要這麼用
可以用iter_d = iter(d) 來用,就相當於d.__iter__
next也一樣
print(next(iter_d)) # 相當於iter_d.__next__()
print(len(d))
就相當於print(d.__len__())
print(iter.d.__iter__().__iter__().__iter__() is iter_d)
上面語句返回的是true,也就是說迭代器的iter返回值就是這個迭代器本身,只是python對於可迭代物件和迭代器物件不寫兩種實現方式了,所以都用相同的方法,返回都是迭代器
print(d.__iter__().__next__())
print(d.__iter__().__next__())
print(d.__iter__().__next__())
以上三條語句的返回值都一樣,都是d產生的迭代器的第一個元素
while True:
try:
v = iter_d.next()
print(v)
except StopIteration:
break
print('第二次取值‘)
#iter_d = d.__iter__() # 沒有這句的話,下面的第二次取值不會取到值,因為iter_d這個迭代器已經在上一次迴圈中取到末尾報異常結束了,如果不重置這個迭代器,就會繼續報異常直接結束取值過程
while True:
try:
v = iter_d.__next__()
print(v)
except StopIteration:
break
以上用try去捕捉異常的寫法太麻煩了,其實for語句的底層機制就和上面的語句一樣
for k in d:
print(k)
for迴圈的底層原理
1.呼叫in後面那個值、物件的__iter__方法,拿到一個迭代器物件iter_obj
2.呼叫迭代器物件iter_obj.__next__()將得到的值返回值賦值給變數名k,迴圈往復直到取值完畢丟擲異常StopIteration
3.捕捉異常結束迴圈
2.生成器
什麼是生成器
生成器就是一個自定義的迭代器
如何得到生成器
單反函式內出現yield關鍵字時,再去呼叫函式時不會立即執行函式體程式碼,會得到一個返回值,該返回值就是生成器物件,即自定義的迭代器
#因為用return的話會直接返回值並且結束程式的執行
def func():
print(‘first’)
yield 1
print(''second')
yield 2
print('third')
yield 3
g = func()
print(g) #g是一個生成器物件
res1 = next(g)
print(res1)
res2 = next(g)
print(res2)
resa3 = next(g)
print(res3)
next(g) # 報錯,沒有值可以取了
總結 yield
1.提供了一種自定義迭代器的解決方案
2.yield&return
相同點:都可以返回值,返回值沒有型別限制、個數限制
不同點: return只能返回一次值,yield卻可以讓函式暫停在某一個位置,可以返回多次值
來用生成器模擬一個range函式
def calc(start,end,step = 1):
while start < end:
yield start
start += step
a = calc(1,10,2) # 返回生成器物件
for i in a:
print(i) # for迴圈取出所有值
3. 函式的遞迴呼叫和二分法
遞迴必須滿足的兩個條件:
1.每進入下一次遞迴呼叫,問題的規模都應該有所減少
2.遞迴必須有一個明確的結束條件
以下遞迴只是單純的重複,沒有意義
def func():
print(1)
print(2)
print(3)
func()
func()
def bar():
print('from bar')
foo()
def foo():
print('from foo')
bar()
foo()
遞迴有兩個明確的階段
1.回溯
2.遞推
如下面的例子
age(5) = age(4)+2
age(4) = age(3)+2
age(3) = age(2)+2
age(2) = age(1)+2
age(1) = 18
def age(n):
if n == 1:
return 18
return age(n-1) + 2
print(age(5))
l=[1,[2,[3,[4,[5,[6,[7,[8,[9,[]]]]]]]]]]
def func(list1):
for item in list1:
if type(item) is not list:
print(item)
else:
func(item)
func(l)
二分法
順序排列的數字中查詢數字
nums=[1,2,3,4,5,6,7,8,9]
def search(nums,find_num):
if len(nums) == 0:
print('not exist')
return
mid = len(nums) // 2
if nums[mid] > find_num:
search(nums[:mid],find_num)
elif nums[mid]<find_num:
search(nums[mid+1:],find_num)
else:
print('get it')
search(nums,9)