函式(查漏補缺)
阿新 • • 發佈:2019-01-04
一、高階函式
高階函式定義: 1.函式接收的引數是一個函式名 2.函式的返回值是一個函式名 3.滿足上述條件任意一個,都可稱之為高階函式
import time def foo(): print('你好啊林師傅') def test(func): print(func) test(foo)
二、函式巢狀
def father(auth_type): def son(): def grandson(): print('我的爺爺是%s' %auth_type) grandson() son() father('filedb')
三、裝飾器(裝飾器=高階函式+函式巢狀+閉包)
普通裝飾器
import time def timmer(func): #func=test def wrapper(): # print(func) start_time=time.time() func() #就是在執行test() stop_time = time.time() print('執行時間是%s' %(stop_time-start_time)) return wrapper @timmer#test=timmer(test) def test(): time.sleep(3) print('test函式執行完畢') test()
帶引數裝飾器
import time def timmer(func): #func=test1 def wrapper(*args,**kwargs): start_time=time.time() func(*args,**kwargs) stop_time = time.time() print('執行時間是%s' %(stop_time-start_time))return wrapper @timmer #test=timmer(test) def test(name,age): time.sleep(3) print('test函式執行完畢,名字是【%s】 年齡是【%s】' %(name,age))
當被修飾函式有返回值的情況
import time def timmer(func): #func=test1 def wrapper(*args,**kwargs): start_time=time.time() res=func(*args,**kwargs) # 接收返回值 stop_time = time.time() print('執行時間是%s' %(stop_time-start_time)) return res # 返回 return wrapper @timmer #test=timmer(test) def test(name,age): time.sleep(3) print('test函式執行完畢,名字是【%s】 年齡是【%s】' %(name,age)) return '這是test的返回值'
裝飾器帶引數的情況(裝飾函式外面在套一層函式還接收變數)
user_list=[ {'name':'alex','passwd':'123'}, {'name':'linhaifeng','passwd':'123'}, {'name':'wupeiqi','passwd':'123'}, {'name':'yuanhao','passwd':'123'}, ] current_dic={'username':None,'login':False} def auth(auth_type='filedb'): def auth_func(func): def wrapper(*args,**kwargs): print('認證型別是',auth_type) if auth_type == 'filedb': if current_dic['username'] and current_dic['login']: res = func(*args, **kwargs) return res username=input('使用者名稱:').strip() passwd=input('密碼:').strip() for user_dic in user_list: if username == user_dic['name'] and passwd == user_dic['passwd']: current_dic['username']=username current_dic['login']=True res = func(*args, **kwargs) return res else: print('使用者名稱或者密碼錯誤') elif auth_type == 'ldap': print('鬼才特麼會玩') res = func(*args, **kwargs) return res else: print('鬼才知道你用的什麼認證方式') res = func(*args, **kwargs) return res return wrapper return auth_func @auth(auth_type='filedb') #auth_func=auth(auth_type='filedb')-->@auth_func 附加了一個auth_type --->index=auth_func(index) def index(): print('歡迎來到京東主頁') @auth(auth_type='ldap') def home(name): print('歡迎回家%s' %name) # @auth(auth_type='sssssss') def shopping_car(name): print('%s的購物車裡有[%s,%s,%s]' %(name,'奶茶','妹妹','娃娃'))
四、迭代器
為何要有迭代器?什麼是可迭代物件?什麼是迭代器物件?
#1、為何要有迭代器? 對於序列型別:字串、列表、元組,我們可以使用索引的方式迭代取出其包含的元素。但對於字典、集合、檔案等型別是沒有索引的,若還想取出其內部包含的元素,則必須找出一種不依賴於索引的迭代方式,這就是迭代器 #2、什麼是可迭代物件? 可迭代物件指的是內建有__iter__方法的物件,即obj.__iter__,如下 'hello'.__iter__ (1,2,3).__iter__ [1,2,3].__iter__ {'a':1}.__iter__ {'a','b'}.__iter__ open('a.txt').__iter__ #3、什麼是迭代器物件? 可迭代物件執行obj.__iter__()得到的結果就是迭代器物件 而迭代器物件指的是即內建有__iter__又內建有__next__方法的物件 檔案型別是迭代器物件 open('a.txt').__iter__() open('a.txt').__next__() #4、注意: 迭代器物件一定是可迭代物件,而可迭代物件不一定是迭代器物件View Code
迭代器物件的使用
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__()) #等同於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迴圈View Code
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,結束迴圈
生成器表示式
#1、把列表推導式的[]換成()就是生成器表示式 #2、示例:生一筐雞蛋變成給你一隻老母雞,用的時候就下蛋,這也是生成器的特性 >>> chicken=('雞蛋%s' %i for i in range(5)) >>> chicken <generator object <genexpr> at 0x10143f200> >>> next(chicken) '雞蛋0' >>> list(chicken) #因chicken可迭代,因而可以轉成列表 ['雞蛋1', '雞蛋2', '雞蛋3', '雞蛋4',] #3、優點:省記憶體,一次只產生一個值在記憶體中View Code
def test(): for i in range(4): yield i t=test() t1=(i for i in t) t2=(i for i in t1) print(list(t1)) print(list(t2)) # 打印出空列表。生成器只有在執行的時候才真正執行。故一開始定義t1、t2兩個生成器根本不會執行,當執行“print(list(t1))”時,生成器t1被list迭代完,故t2不會執行,注意不是報錯
五、函式作用域
#1、作用域即範圍 - 全域性範圍(內建名稱空間與全域性名稱空間屬於該範圍):全域性存活,全域性有效 - 區域性範圍(區域性名稱空間屬於該範圍):臨時存活,區域性有效 #2、作用域關係是在函式定義階段就已經固定的,與函式的呼叫位置無關,如下 x=1 def f1(): def f2(): print(x) return f2 x=100 def f3(func): x=2 func() x=10000 f3(f1()) #3、檢視作用域:globals(),locals() LEGB 代表名字查詢順序: locals -> enclosing function -> globals -> __builtins__ locals 是函式內的名字空間,包括區域性變數和形參 enclosing 外部巢狀函式的名字空間(閉包中常見) globals 全域性變數,函式定義所在模組的名字空間 builtins 內建模組的名字空間
六、閉包
閉包的意義與應用
#閉包的意義:返回的函式物件,不僅僅是一個函式物件,在該函式外還包裹了一層作用域,這使得,該函式無論在何處呼叫,優先使用自己外層包裹的作用域 #應用領域:延遲計算(原來我們是傳參,現在我們是包起來) from urllib.request import urlopen def index(url): def get(): return urlopen(url).read() return get baidu=index('http://www.baidu.com') print(baidu().decode('utf-8'))
七、遞迴
1. 必須有一個明確的結束條件 2. 每次進入更深一層遞迴時,問題規模相比上次遞迴都應有所減少 3. 遞迴效率不高,遞迴層次過多會導致棧溢位(在計算機中,函式呼叫是通過棧(stack)這種資料結構實現的,每當進入一個函式呼叫,棧就會加一層棧幀,每當函式返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞迴呼叫的次數過多,會導致棧溢位)
遞迴呼叫應該分為兩個明確的階段:遞推,回溯
#1、遞迴呼叫應該包含兩個明確的階段:回溯,遞推 回溯就是從外向裡一層一層遞迴呼叫下去, 回溯階段必須要有一個明確地結束條件,每進入下一次遞迴時,問題的規模都應該有所減少(否則,單純地重複呼叫自身是毫無意義的) 遞推就是從裡向外一層一層結束遞迴 #2、示例+圖解。。。 # salary(5)=salary(4)+300 # salary(4)=salary(3)+300 # salary(3)=salary(2)+300 # salary(2)=salary(1)+300 # salary(1)=100 # # salary(n)=salary(n-1)+300 n>1 # salary(1) =100 n=1 def salary(n): if n == 1: return 100 return salary(n-1)+300 print(salary(5))View Code