瞭解無參裝飾器的實現原理後,咱們能夠再實現一個用來爲被裝飾對象添加認證功能的裝飾器,實現的基本形式以下python
def deco(func): def wrapper(*args, **kwargs): #編寫基於文件的認證,認證經過則執行res=func(*args, **kwargs),並返回res return wrapper
若是咱們想提供多種不一樣的認證方式以供選擇,單從wrapper函數的實現角度改寫以下mysql
def deco(func): def wrapper(*args, **kwargs): if driver == 'file': print('基於文件認證經過') res = func(*args, **kwargs) return res elif driver == 'mysql': print('基於數據認證經過') res = func(*args, **kwargs) return res print('...') return wrapper
函數wrapper須要一個driver參數,而函數deco與wrapper的參數都有其特定的功能,不能用來接受其餘類別的參數,能夠在deco的外部再包一層函數auth,用來專門接受額外的參數,這樣便保證了在auth函數內不管多少層均可以引用到sql
def auth(driver): def deco(func): def wrapper(*args, **kwargs): if driver == 'file': print('基於文件認證經過') res = func(*args, **kwargs) return res elif driver == 'mysql': print('基於數據認證經過') res = func(*args, **kwargs) return res print('...') return wrapper return deco @auth(driver='aaa')#這裏由於咱們傳入的參數沒有 #下面爲該語法糖最後表明的內容 #--->@和auth(driver='aaa')--->而auth(driver='aaa')至關因而調用函數auth獲得結果爲deco函數的內存地址,即此時這裏爲@deco,這裏咱們也能夠將其分開爲@和deco--->而@的做用就是至關於將被裝飾對象的函數名看成參數傳入該函數,因此如今就爲deco(index),而該函數的結果爲wrapper,因此這裏咱們能夠寫爲wrapper=deco(index),即wrapper=wrapper --->因此最後咱們調用的函數實際上是wrapper,可是裝飾器的原則之一爲不修改被裝飾對象的調用方式,因此咱們能夠將wrapper函數對應的內存地址定義一個變量index=wrapper。 def index(): print('from index') index() #輸出結果爲 ...
可使用help(函數名)來查看函數的文檔註釋,本質就是查看函數的__doc__屬性,但對於被裝飾以後的函數,查看文檔註釋app
import time def timer(func): def wrapper(*args, **kwargs): start_time = time.time() res = func(*args, **kwargs) end_time = time.time() print('run time is %s'%(end_time - start_time)) return res return wrapper @timer def home(name): ''' home page function :param name:str :return:None ''' time.sleep(5) print('Welcome to the home pae', name) print(help(home)) #輸出結果爲 Help on function wrapper in module __main__: wrapper(*args, **kwargs) None Process finished with exit code 0
在被裝飾以後home=wrapper,查看home.__name__也能夠發現home的函數名確實是wrapper,想要保留原函數的文檔和函數名屬性,須要修正裝飾器函數
def timer(func): def wrapper(*args,**kwargs): start_time=time.time() res=func(*args,**kwargs) stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return res wrapper.__doc__=func.__doc__ wrapper.__name__=func.__name__ return wrapper
按照上述方式來實現保留原函數屬性過於麻煩,functools模塊下提供一個裝飾器wraps專門用來幫咱們實現這件事,用法以下工具
from functools import wraps def timer(func): @wraps(func) def wrapper(*args,**kwargs): start_time=time.time() res=func(*args,**kwargs) stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return res return wrapper
迭代器
迭代的工具。code
迭代: 迭代指的是重複迭代,每一次迭代都是基於上一次的結果而來的。 迭代器: 迭代器指的是迭代取值的工具,它能夠迭代取值。 - 若是想要知道python中迭代器是什麼?必須先知道什麼是可迭代對象? - 可迭代對象: 全部的序列類型: str, list, tuple, dict, set, f 凡是內部有str.__iter__()方法的都是可迭代對象。 - 獲取迭代器: 經過可迭代對象.__iter__(), 獲得的返回值就是 「迭代器對象」。 迭代器是迭代取值的工具,做用是迭代取值。 - 如何迭代取值: 迭代器對象.__next__() # 「每一次執行」,都會從迭代器對象中取出一個值 - 總結: 可迭代對象 VS 迭代器對象: - 獲取可迭代對象: 定義序列類型(str, list, set, tuple, dict, f) - 特色: 內置有__iter__() - 獲取迭代器對象: 經過可迭代對象調用.__iter__()獲得返回值 - 特色: 內置有__next__() - 迭代器對象的優勢: - 優勢: 1.不依賴於索引迭代取值。 2.節省內存空間。 - 缺點: 1.取指定某個值麻煩 2.每次取值都要從第一個值開始,沒法同過索引取值。 for循環原理 語法: for i in 可迭代對象: in: 可迭代對象 ----> 內部會自動調用.__iter__() ---> 迭代器對象 for line in list1: # 迭代器對象.__next__() - 迭代器本質上是一個可迭代對象 - 文件本質上既是迭代器對象,也是可迭代對象。 - 可迭代對象不必定是迭代器對象