Python 三程三器的那些事
- 2020 年 3 月 10 日
- 筆記
裝飾器
1、什麼是裝飾器
- 裝飾器本質是函數,用來給其他函數添加新的功能
- 特點:不修改調用方式、不修改源程式碼
2、裝飾器的作用
- 裝飾器作用:本質是函數(裝飾其他函數)就是為其他函數添加其他功能
- 裝飾器必須准尋得原則:
- 不能修改被裝飾函數的源程式碼、不能修改被裝飾函數的調用方式
- 實現裝飾器知識儲備:
- 函數即“變數”
- 高階函數
- 嵌套函數 高階函數+潛逃函數=》裝飾器
3、使用高階函數模仿裝飾器功能
1.定義:把一個函數名當做實參傳給另一個函數
2.返回值中包含函數名
3.下面使用高階函數雖然可以實現裝飾器的一些功能,但是違反了裝飾器不能改變調用方式的原則,
以前使用bar()現在將調用方式改編成了test1(bar)就是將bar的函數名當做變數傳給了test1()
#! /usr/bin/env python # -*- coding: utf-8 -*- import time def timer(func): start_time = time.time() func() print '函數執行時間為', time.time() - start_time def test(): print '開始執行test' time.sleep(3) print 'test執行結束' timer(test) ''' 開始執行test test執行結束 函數執行時間為 3.00332999229 '''
改變了調用方式
4.高階函數——不修改高階函數的調用方式增加新的功能(但是無法傳參數)
註:bar = test2(bar) 等價於:@timer重新將函數名bar賦值,將原函數bar的記憶體地址當做實參傳遞該函數test2(),再將test2()賦值給bar
import time def bar(): time.sleep(3) print("in the bar") def test2(func): print(func) return func bar = test2(bar) bar()
不改變調用方式
5.嵌套函數
嵌套函數:在一個函數中嵌套另一個函數,並在函數內部調用
def foo(): print("in the foo") def bar(): print("in the bar") bar() foo()
嵌套函數
4、能夠適應90%的業務需求
- 在裝飾器中 @timer等價於 test1=timer(test1)
- 在timer()函數中返回值是return deco
- 所以timer(test1)作用是將函數test1記憶體地址當做參數傳遞給timer()
- timer() 函數最後將運行後的函數deco記憶體地址作為返回值返回
- test1=timer(test1)作用就是將將deco函數記憶體地址賦值給test1,所以最後運行test1()就相當於運行deco()
- 所以最後調用時給test2()傳入參數就相當於給deco傳入參數
import time def timer(func): #timer(test1) func=test1 def deco(*args,**kwargs): start_time = time.time() func(*args,**kwargs) #run test1 stop_time = time.time() print("running time is %s"%(stop_time-start_time)) return deco @timer # test1=timer(test1) def test1(): time.sleep(3) print("in the test1") @timer def test2(name): print("in the test2",name) test1() test2("tom")
裝飾器1
5、對特定網頁進行身份驗證
import time user,passwd = 'aaa','123' def auth(func): def wrapper(*args,**kwargs): username = input("Username:").strip() password = input("Password:").strip() if user == username and password == passwd: print("User has passed authentication") res = func(*args,**kwargs) #這裡執行func()相當於執行調用的函數如home() return res #為了獲得home()函數返回值,可以將執行結果賦值給res然後返回print(home())結果是"from home"而不是"None"了 else: exit("Invalid username or password") return wrapper def index(): print("welcome to index page") @auth def home(): print("welcome to home page") return "from home" @auth def bbs(): print("welcome to bbs page") index() print(home()) #在這裡調用home()相當於調用wrapper() bbs()
裝飾器2
6、實現對不同網頁不同方式的身份認證
- @auth(auth_type=“local”)程式碼作用
- 在上面的程式碼中使用@auth相當於先將home函數的記憶體地址當做變數傳入auth()函數,執行結果後home()相當於wrapper()
- 而在這裡驗證的時候猶豫@auth(auth_type=”local”)中有()括弧,那麼就相當於將執行auth()函數而且是將auth_type=“local當做參數傳入到auth()函數執行
- 所以outer_wrapper函數也會執行,outer_wrapper函數的執行結果返回的就是wrapper()函數的記憶體地址
- 所以最終結果同樣是執行home()函數就相當於執行wrapper函數
- 但是有所不同的是著這個版本中我們可以在外層的auth函數中傳入新的參數幫組我們根據需求判斷
import time user,passwd = 'aaa','123' def auth(auth_type): print("auth func:",auth_type) def outer_wrapper(func): def wrapper(*args, **kwargs): print("wrapper func args:", *args, **kwargs) if auth_type == "local": username = input("Username:").strip() password = input("Password:").strip() if user == username and passwd == password: print("