一、什麼是裝飾器?面試
不修改函數的調用方式,還能再原來函數的基礎上增長功能。app
二、裝飾器原則:開放封閉原則ide
開放:對擴展時開放的函數
封閉:對修改是封閉的spa
三、裝飾器的通用寫法:code
def wrapper(func): # 裝飾器 def inner(*args, **kwargs): # 利用*args和**kwargs接受任意參數:位置參數和關鍵字參數 ret = func(*args, **kwargs) # 接收函數的返回值 return ret return inner @wrapper # 裝飾器的重點:語法糖:這裏其實是wahaha = wrapper(wahaha),不過這樣寫應該寫到定義的函數後 def wahaha(a,b): # 原函數 sum = a + b return sum ret = wahaha(3, 4) # 函數調用且接受返回值 print(ret)
ps:小知識補充一:time模塊對象
import time # 導入time模塊 def wrapper(func): def inner(*args, **kwargs): start = time.time() # time()能夠查看當前時間(從1970到如今) ret = func(*args, **kwargs) end = time.time() print(end - start) # 能夠查看代碼執行時間 return ret return inner @wrapper def wahaha(a,b): sum = a + b time.sleep(0.1) # 讓代碼中止0.1秒 return sum # wahaha = wrapper(wahaha) ret = wahaha(3, 4) print(ret)
四、裝飾器進階blog
完美裝飾器內存
import time from functools import wraps def wrapper(func): @wraps(func) # 完美裝飾函數 def inner(*args, **kwargs): start = time.time() ret = func(*args, **kwargs) end = time.time() print(end - start) return ret return inner @wrapper def wahaha(a,b): sum = a + b time.sleep(0.1) return sum print(wahaha.__name__) # 查看函數名
五、帶參數的裝飾器generator
import time from functools import wraps flag = 1 # 經過設置標誌位可與以使用戶更方便的決定用或不用裝飾器 def Flag(flag): # 在本來裝飾器的外層再套一層裝飾器,進行一次參數的傳遞 def wrapper(func): @wraps(func) def inner(*args, **kwargs): if flag: start = time.time() ret = func(*args, **kwargs) end = time.time() print(end - start) return ret else: ret = func(*args, **kwargs) return ret return inner return wrapper @Flag(flag) def wahaha(a,b): sum = a + b time.sleep(0.1) return sum ret = wahaha(1,2) print(ret)
六、多個裝飾器裝飾同一個函數
def wrapper1(func): # 1 def inner1(*args, **kwargs): # 4 print('before func inner1') # 14 ret1 = func(*args, **kwargs) # 15 wahaha() # 18 ret1 = 123 print('after func inner1') # 19 return ret1 # 20 return inner1 # 5 def wrapper2(func): # 2 def inner2(*args, **kwargs): # 8 print('before func inner2') # 12 ret2 = func(*args, **kwargs) # 13 inner1() # 21 ret2 = ret1 = 123 print('after func inner2') # 22 return ret2 #23 return inner2 # 9 @wrapper2 # 7 wrapper2(inner1) # 10 wahaha = inner2 @wrapper1 # 3 wrapper1(wahaha) # 6 wahaha = inner1 def wahaha(): print('wahaha is good') # 16 return 123 # 17 ret = wahaha() # 11 inner2() #24 ret = ret2 = 123 print(ret) # 25
一、雙下方法:__iter__()加了雙下劃線的方法
二、可迭代協議:只要含有__iter__方法的都是可迭代的 判斷方法:'__iter__'in dir(方法名)
能夠被for循環的都是可迭代的
三、迭代器協議:內部含有__iter__和__next__的方法就是迭代器 判斷方法: '__iter__' in dir() and '__next__'in dir()
可迭代的.__iter__()就獲得一個迭代器
迭代器中的__next__()方法能夠一個一個的獲取值
for循環其實就是在使用迭代器
四、迭代器的優勢:
(1)使用方便,一個迭代器只能從頭至尾取值,且只能取一次
(2)節省內存空間(可迭代對象是一個個給你而不是一次性讀取,不會佔用大塊內存,每次只給一個)
l = [1, 2, 3, 4, 5] g = l.__iter__() print(g.__next__()) # 每次返回列表中的一個值 print(g.__next__()) # 每次返回列表中的一個值 print(g.__next__()) # 每次返回列表中的一個值 print(g.__next__()) # 每次返回列表中的一個值
一、本質上是一種迭代器,生成器與迭代器都是惰性運算
二、生成器函數:本質上就是咱們本身寫的函數,只要含有yield的函數都是生成器函數,且yield不能與return共用,且只能在函數內使用
生成器函數執行一次後得到一個生成器,此時函數並無執行
三、生成器:
yield在返回值時和return有着相同的做用
def generater(): print(1) yield 'a' print(2) yield 'b' g = generater() # 此時只是得到一個生成器 ret = g.__next__() # g.__next__()這時函數才真正執行,執行到第一個yield處 print(ret) ret = g.__next__() # g.__next__()函數接着上次中止的地方執行,執行到下一個yield處 print(ret)
由於生成器的本質是迭代器,因此一個生成器只能從頭至尾取一次值,當取完值時在執行生成器.__next__()會報錯
四、從生成器中取值的幾個方法:
next、for循環、數據類型的強制轉換(比較佔用內存)
五、生成器函數進階一:send函數
def generator(): content = yield 1 print('===',content) content = yield 2 print('***',content) content = yield 3 g = generator() ret = g.__next__() # 在第一次使用生成器時,需用next獲取到一個值 print(ret) ret = g.send(10) # send函數與next函數都有獲取下一個值的效果,但send函數能夠在上一個yield的地方傳一個參數 print(ret) ret = g.send(20) print(ret) ret = g.send(30) # 最後一個yield不能接收外部的值 print(ret)
六、生成器函數進階二:獲取移動平均值
def average(): sum = 0 count = 0 avg = 0 while True: num = yield avg # 生成器激活到這裏就中止 sum += num count += 1 avg = sum/count a = average() a.__next__() # 激活生成器 a1 = a.send(10) # 在中止位置給num傳一個值 a2 = a.send(20) print('%s,%s'%(a1,a2))
ps:小技巧
def generator(): a = 'asdfg' b = '12345' yield from a # 可迭代類型數據均可以 yield from b g = generator() for i in g: print(i)
七、生成器表達式
1)列表推導式
list=['%s'%i for i in [1,2,3,4,5] if i>3] print(list)
2)生成器表達式
g = (i for i in range(10)) for i in g: print(i)
生成器表達式與列表推導式的括號不一樣,返回的值不一樣。生成器表達式返回的是一個生成器,幾乎不佔用內存。
當碰到列表推導式相關面試題時,能夠展開進行一步步的推導。
3)字典推導式
# 將字典的鍵值互換 dic = {1:'a',2:'b'} dic1 = {dic[i]:i for i in dic} print(dic1)
4)集合推導式
set1 = {i**i for i in [1,-1,2]} print(set1) # 集合自帶去重功能