迭代定義:html
迭代是重複反饋過程的活動,其目的一般是爲了逼近所需目標或結果。每一次對過程的重複稱爲一次「迭代」,而每一次迭代獲得的結果會做爲下一次迭代的初始值。python
1迭代器協議:對象必須提供一個__next__() 方法,執行該方法要麼返回迭代中的下一項,要麼就引發一個StopIteration異常,以終止迭代(只能往前,不能退後)編程
2可迭代對象(迭代器):實現了迭代器協議的對象(如何實現迭代器協議,在對象內部定義__iter__()方法微信
3協議是一種約定,可迭代對象實現了迭代器協議,Python的內部函數工具(如for循環,sum,min,max函數等)都是使用迭代器協議訪問對象!!!閉包
迭代器做用:能夠節省內存併發
迭代器相關的方法:iter() 和 next()。app
python內置函數 next() 本質就是在調用__next__()ide
>>> list=[1,2,3,4] >>> it = iter(list) # 建立迭代器對象 >>> print (next(it)) # 輸出迭代器的下一個元素 1 >>> print (next(it)) 2 >>>
經過iter()還能夠指定迭代至結束時的對象函數
l = ['a', 'b', 'c', 'd'] def test(): return l.pop() x = iter(test, 'b') print(x.__next__()) #d print(x.__next__()) #c print(x.__next__()) #到'b'了,拋異常
(字符串str,列表list,元組tunple,字典dict,,集合set,文件對象)這些都不是可迭代對象,只不過在for循環,調用了他們的內部的__iter__()方法,把他們變成了可迭代對象,(補充:爲何str,list,tunple能夠有下標,例如list[0],由於他們是有序的)工具
for循環把他們變成了可迭代對象後,就調用可迭代對象的_next()_方法去取值,並且for循環會捕獲StopIteration異常,以終止迭代!!!
1 name = 'ales' 2 print(n) 3 4 輸出結果 5 <str_iterator object at 0x00E7EF90>
for循環就是基於迭代器協議提供一個統一的能夠遍歷全部對象的方法,即在遍歷以前,先調用對象的__iter__()方法將其轉換成一個迭代器,而後使用迭代器協議去實現循環訪問。這樣全部的對象均可以經過for循環來遍歷。name = 'ales'n = name.__iter__() #遵循迭代協議,調用_iter_方法生成可迭代對象
print(n.__next__()) print(n.__next__()) print(n.__next__()) print(n.__next__()) print(n.__next__())# 迭代至StopIteration異常 輸出結果 a l e s Traceback (most recent call last): File "E:/PycharmProjects/untitled/day18/迭代器.py", line 9, in <module> print(n.__next__()) StopIteration
利用while模仿for循環
1 list1 = [1, 2, 3, 4] 2 l = list1.__iter__() 3 while True: 4 try: 5 print(l.__next__()) 6 except StopIteration: 7 break
執行結果
1
2
3
4
什麼是生成器
能夠理解爲一種數據類型,這種數據類型自動實現了迭代器協議,其餘的數據類型須要須要調用本身內置的__iter__方法,因此生成器就是可迭代對象
python中有兩種方式提供生成器:
1.生成器函數:常規函數定義,可是使用yield語句而不是return語句返回結果。yield語句一次返回一個結果,在每一個結果中,掛起函數的狀態,以便下次從它離開的地方繼續執行
2.生成器表達式:相似於列表解析,可是生成器返回按需產生結果的一個對象,而不是一次構建出的結果列表
def test(): yield 1 yield 2 yield 3 x = test() print(x) print(x.__next__()) print(x.__next__()) print(x.__next__()) print(x.__next__()) 執行結果 <generator object test at 0x00C834F0> 1 2 3 print(x.__next__()) StopIteration
生成器函數和普通函數
普通函數
# 普通函數 def test(): print('start') test() 運行結果 start
生成器函數
# 生成器函數是一個可迭代對象,注意與普通函數的區別 def test(): print('start') yield '這是第一個yield語句的返回值' print('這是第一個yield的下一行') yield '這是第二個yield語句的返回值' print('這是第二個yield的下一行') yield '這是第三個yield語句的返回值' print('這是第三個yield的下一行') a = test() #生成一個可迭代對象 print(a) print(type(a)) 運行結果 <generator object test at 0x02DF35B0> <class 'generator'>
接上
第一種
a.__next__() #運行至第一個yield語句結束,並保留運行狀態 a.__next__() #從上次的運行狀態開始,運行至第二個yield語句結束 a.__next__() 運行結果 start 這是第一個yield的下一行 這是第二個yield的下一行
第二種
res = a.__next__() ##運行至第一個yield語句結束,保留運行狀態,並將yield的返回值賦值給res print(res) 運行結果 start 1
第三種
res = a.__next__() #運行至第一個yield語句結束,保留運行狀態,並將yield的返回值賦值給res print(res) a.__next__() #從上次的運行狀態開始,運行至第二個yield語句結束 運行結果 start 這是第一個yield語句的返回值 這是第一個yield的下一行
num = ('num%d' %i for i in range(10))#生成器表達式 print(num) print((num.__next__())) print((num.__next__())) print(next(num)) print(next(num)) 運行結果 <generator object <genexpr> at 0x00AA34F0> num0 num1 num2 num3
列表解析和生成器表達式
>>> l = [i for i in range(0,15)] #列表解析 >>> print(l) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] >>> m = (i for i in range(0,15)) #生成器表達式 >>> print(m) <generator object <genexpr> at 0x104b6f258> >>> for g in m: ... print(g,end=', ') ... 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
把列表解析的 [ ] 換成 ( ) 獲得的就是生成器表達式
列表解析和生成器表達式都是遍歷的編程方式,可是生成器表達式更節省內存
# 列表解析 print([i for i in range(1,1000000)]) #內存佔用過大,機器易卡死 # 生成器表達式 m = (i for i in range(1,100000000)) #幾乎不佔內存,運行的時間取決於cpu print(sum(m))
python大部份內置函數都是使用迭代器協議訪問對象。如 sum()
sum(x**2 for x in range(4)) sum([x ** 2 for x in range(4)]) #不用畫蛇添足構造列表
__next__()在生成器函數中能夠運行至函數的下一個yield語句結束,並保留運行狀態,返回yield語句定義的返回值
next() 返回迭代器的下一個項目。
內置函數 next() 本質就是在調用__next__()
def test(): print('start') first = yield 1 print('這是第一個yield的下一行', first) second = yield 2 print('這是第二個yield的下一行', second) yield t = test() #產生生成器 print(t.__next__()) #第一次運行只能使用next或者send(None) t.send('this is the first send value') #send具備next的功能,讓程序運行到下一個yield語句結束 t.send('this is the second send value')
運行結果
start 1 這是第一個yield的下一行 this is the first send value 這是第二個yield的下一行 this is the second send value Process finished with exit code 0
import time def eat_grass(name): print('我是%s,我準備開始吃牧草了' % name) while True: grass = yield time.sleep(1) print('我開心地吃了第%s棵牧草' %grass) # name = 'cow' # eg = eat_grass(name) # eg.__next__() # eg.send('grass_number_01') # eg.send('grass_number_02') # eg.send('grass_number_03') def product_grass(): name = 'cow' eg = eat_grass(name) eg.__next__() for i in range(1,10): time.sleep(1) eg.send('%d' %i) product_grass()
以生成器函數爲例進行總結:
一、語法上和函數相似:差異在於常規函數只能使用一個return語句返回值,而生成器可使用多個yield語句返回值
二、自動實現迭代器協議:Python對於生成器自動實現了迭代器協議,因此能夠調用 next,並在沒有值能夠next的時候,生成器自動產生StopIteration異常。還能夠應用到迭代背景中(如for循環,sum函數)
三、狀態掛起:生成器使用yield語句返回一個值,此時yield語句掛起該生成器函數的狀態,保留足夠信息,以便以後的使用都是基於最新的狀態
優勢:
一、生成器的好處時延遲計算,一次返回一個結果。這樣能夠節省內存,提升運行效率。對大數據處理很是有用。
見列表解析和生成器表達式的對比
二、生成器能夠提供代碼的可讀性
注意:生成器只能遍歷一次(例如生命只有一次,且年齡只會愈來愈大,不能返老還童)
l = [i for i in range(10)]#列表解析 print(l) # 等價於 l = [] for i in range(10): l.append(i) print(l)
age = 20 res = 'adult' if age>20 else 'child' #三元表達式 print(res) # 等價於 age = 20 res = '' if age > 20: res = 'adult' else: res = 'child' print(res)
裝飾即修飾,意指爲其餘函數添加新功能;
裝飾器的本質就是函數
做用是爲其餘函數添加新功能,如計算該函數運行時長
裝飾器遵循原則:
1.不修改被裝飾函數的源代碼(開放封閉原則)
2.爲被裝飾函數添加新功能後,不能修改被修飾函數的調用方式
裝飾器的實現 = 高階函數 + 函數嵌套 + 閉包
高階函數 = 函數接收的參數是一個函數名 或 函數返回值包含函數名
參數是一個函數名,能夠爲被修飾函數添加新功能
返回值包含函數,能夠不改變被修飾函數的調用方式
1 # 高階函數:參數包含函數名;或者返回值包含函數名 2 3 import time 4 5 def foo(): 6 time.sleep(1) 7 print('this is from foo') 8 9 def deco(func): #參數是一個函數名,能夠爲被修飾函數添加新功能 10 starttime = time.time() 11 func() 12 endtime = time.time() 13 print('運行%s函數共耗時%f' %(func,endtime-starttime)) 14 return func #返回值包含函數,能夠不改變被修飾函數的調用方式 15 16 foo = deco(foo) 17 foo() 18 # 缺陷:這裏被修飾函數運行了兩次,因此生成器不能只靠高階函數!
函數嵌套:在函數體中定義函數
閉包:閉包就是可以讀取其餘函數內部變量的函數。在一個做用域裏放入定義變量,至關於打了一個包
def country(address): # name = 'alex' print('this is from country') def province(): # name = 'blice' print('this is from province %s' %address) country('個人地址')
1 import time 2 3 def deco(func): 4 def qiantao(): 5 starttime = time.time() 6 func() 7 endtime = time.time() 8 print('運行%s函數共耗時%f' %(func,endtime-starttime)) 9 return qiantao 10 11 12 def foo(): 13 time.sleep(1) 14 print('this is from foo') 15 16 17 foo = deco(foo) #deco(foo)就是qiantao 18 foo() #這裏foo()至關於qiantao()
1 import time 2 3 def deco(func): 4 def qiantao(): 5 starttime = time.time() 6 res = func() 7 endtime = time.time() 8 print('運行%s函數共耗時%f' %(func,endtime-starttime)) 9 return res 10 return qiantao 11 12 13 @deco #就至關於在調用foo()以前執行 foo = deco(foo) 14 def foo(): 15 time.sleep(1) 16 print('this is from foo') 17 return 'foo的返回值' 18 19 20 # foo = deco(foo) 21 res = foo() 22 print(res)
1 import time 2 3 def deco(func): 4 def qiantao(*args, **kwargs): # args=(name, age) kwargs={gender:male,} 5 starttime = time.time() 6 res = func(*args, **kwargs) #*(name,age) **{gender:male} 7 endtime = time.time() 8 print('運行%s函數共耗時%f' %(func,endtime-starttime)) 9 return res 10 return qiantao 11 12 female = '女' 13 @deco #就至關於在調用foo()以前執行 foo = deco(foo) 14 def foo(name, age, gender=female): 15 time.sleep(1) 16 print('this is from foo, =====> my name is %s ,age is %s, gender is %s' %(name, age,gender)) 17 return 'foo的返回值' 18 19 res = foo('liming', 18, gender = '男') 20 print(res)
應用實例:
1 user_list = [{'name':'alex', 'pwd':'123'}, 2 {'name':'belief', 'pwd':'123'}, 3 {'name':'a', 'pwd':'123'},] 4 5 current_dic = {'username':'','login':False} 6 7 def auth_fun(fun): 8 def warp(*args, **kwargs): 9 if current_dic['username'] and current_dic['login']: 10 res = fun(*args, **kwargs) 11 return res 12 username = input('please input your name>') 13 password = input('please input your password>') 14 for user_dic in user_list: 15 if username==user_dic['name'] and password==user_dic['pwd']: 16 current_dic['username'] = username 17 current_dic['login'] = True 18 res = fun(*args, **kwargs) 19 return res 20 else: 21 print('用戶名或密碼錯誤') 22 return warp 23 24 # index = auth_fun(index) 25 @auth_fun 26 def index(): 27 print('歡迎訪問該網站') 28 29 @auth_fun 30 def home(name): 31 print('這是的%s家頁面' %name) 32 33 @auth_fun 34 def shopping_car(name): 35 print('%s的購物車裏有%s' %(name, '衣服')) 36 37 index() 38 # home('belief') 39 # shopping_car('belief')
1 user_list = [{'name':'alex', 'pwd':'123'}, 2 {'name':'belief', 'pwd':'123'}, 3 {'name':'a', 'pwd':'123'},] 4 5 current_dic = {'username':'','login':False} 6 7 def auth(type='qq'): 8 '''根據用戶的登陸方式來進行登陸操做''' 9 def auth_fun(fun): 10 def warp(*args, **kwargs): 11 print('登陸方式是%s' %type) 12 if type=='qq': 13 if current_dic['username'] and current_dic['login']: 14 res = fun(*args, **kwargs) 15 return res 16 username = input('please input your name>') 17 password = input('please input your password>') 18 for user_dic in user_list: 19 if username==user_dic['name'] and password==user_dic['pwd']: 20 current_dic['username'] = username 21 current_dic['login'] = True 22 res = fun(*args, **kwargs) 23 return res 24 else: 25 print('用戶名或密碼錯誤') 26 elif type=='wx': 27 print('打開微信掃一掃') 28 else: 29 print('不支持其餘登陸方式,請使用qq或微信') 30 return warp 31 return auth_fun 32 33 # index = auth_fun(index) 34 @auth(type='qq') #autn(type='qq')就是auth_fun @auth_fun至關於index=auth_fun(index), 即index = warp 35 def index(): 36 print('歡迎訪問該網站') 37 38 @auth(type='wx') 39 def home(name): 40 print('這是的%s家頁面' %name) 41 42 @auth(type='sj') 43 def shopping_car(name): 44 print('%s的購物車裏有%s' %(name, '衣服')) 45 46 # index() 47 home('belief') 48 # shopping_car('belief')
https://www.runoob.com/python3/python3-iterator-generator.html