"""
裝飾器
定義:本質是函式(器:就是函式的意思),功能:裝飾其他函式,就是為其他函式新增附加功能
原則:
1. 不能修改被裝飾的函式的原始碼
2. 不能修改被裝飾的函式的呼叫方式
實現裝飾器知識儲備:
1. 函式即"變數"
2. 高階函式
a: 把一個函式名當做實參傳給另一個函式(在不修改被裝飾函式原始碼的情況下為其新增功能)
b: 返回值中包含函式名 (不修改函式的呼叫方式)
3. 巢狀函式
高階函式 + 巢狀函式 --> 裝飾器
參考連結:http://egon09.blog.51cto.com/9161406/1836763
"""
# 將test1 和 test2 函式新增logging 功能 (未使用使用函式呼叫)
''' def logger(): print ("logging") def test1(): pass logger() def test2(): pass logger() test1() test2() '''
# 裝飾器示範_1
''' import time def timmer(func): def warpper(*args,**kwargs): start_time = time.time() func() stop_time = time.time() print ("the func run time is %s"%(stop_time - start_time)) return warpper @timmer def test1(): time.sleep(3) print ("this is test1") test1() # this is test1 # the func run time is 3.019197702407837 '''
# 函式即"變數"
# 新概念:函式在記憶體中以變數形式存放
# 匿名函式沒有函式名,當執行後記憶體會被立馬回收(def 定義的函式,不會被記憶體回收,當程式結束後記憶體地址才會釋放)
''' # eg_v1 def bar(): # 正常執行 print ("in the bar") def foo(): print ("in the foo") bar() foo() # in the foo # in the bar # eg_v2 # 正常執行 def foo(): print ("in the foo") bar() def bar(): print ("in the bar") foo() # in the foo # in the bar # eg_v3 # 丟擲異常 def foo(): print ("in the foo") bar() foo() def bar(): print ("in the bar") # Traceback (most recent call last): # in the foo # File "E:/pycharm-project/PYTHON自動化課程/第二模組/課堂筆記/裝飾器_v1.py", line 92, in <module> # foo() # File "E:/pycharm-project/PYTHON自動化課程/第二模組/課堂筆記/裝飾器_v1.py", line 91, in foo # bar() # NameError: name 'bar' is not defined '''
# 高階函式
# eg_v1 ''' def bar(): print ("in the bar") def test1(func): print (func) # test1(bar) # # <function bar at 0x0000024DE92E3E18> bar函式的記憶體地址 ''' # eg_v2 ''' def bar(): print ("in the bar") def test1(func): print (func) func() # 2 呼叫func函式時,也執行了bar函式 test1(bar) # 1 將bar函式傳遞給test1 # <function bar at 0x00000216F49D3E18> # in the bar ''' # eg_v3 # 裝飾器第一步(沒有修改原始碼,但改變了呼叫方式)(test1為裝飾函式,bar函式為被裝飾函式) ''' import time def bar(): time.sleep(2) print ("in the bar") def test1(func): start_time = time.time() func() stop_time = time.time() print ("the func run time is %s"%(stop_time - start_time)) test1(bar) # in the bar # the func run time is 2.000016689300537 ''' # eg_v4 ''' import time def bar(): time.sleep(2) print("in the bar") def test2(func): print (func) return func # t = test2(bar) # 將test2(bar) 賦值給t,t() == 呼叫test2函式,改變了呼叫方式 # t() # # <function bar at 0x00000172B2CF3E18> # # in the bar bar = test2(bar) # # 將test2(bar) 賦值給bar,bar() == 呼叫test2函式,未改變了呼叫方式 bar() # <function bar at 0x0000016C6E663E18> # in the bar '''
# 巢狀函式
# eg_v1 ''' def foo(): print ("in the foo") def bar(): print ("in the bar") bar() foo() ''' # eg_v2 # 區域性作用域和全域性作用域的訪問順序 ''' x = 0 def grandpa(): x = 1 def dad(): x = 2 def son(): x = 3 print (x) son() dad() grandpa() # 3 '''
# 寫一個簡單的裝飾器
# eg_v1 不使用語法糖
''' import time def timer(func): # timer(test1) --> func= test1 def deco(): start_time = time.time() func() # run test1() stop_time = time.time() print ("the func run time %s:"%(stop_time - start_time)) return deco def test1(): time.sleep(3) print ("in the test1") def test2(): time.sleep(3) print ("in the test2") test1 = (timer(test1)) # 賦值必須與被裝飾的函式同名 test1() # in the test1 # the func run time 3.0068588256835938: '''
# eg_v2 使用語法糖,不帶引數
''' import time def timer(func): # timer(test1) --> func= test1 def deco(): start_time = time.time() func() # run test1() stop_time = time.time() print ("the func run time %s:"%(stop_time - start_time)) return deco @timer def test1(): time.sleep(3) print ("in the test1") @timer def test2(): time.sleep(3) print ("in the test2") test1() test2() # in the test1 # the func run time 3.000098705291748: # in the test2 # the func run time 3.0001633167266846: '''
# eg_v2 使用語法糖,被裝飾函式帶引數
''' 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 ("the func run time %s:"%(stop_time - start_time)) return deco @timer def test1(): time.sleep(3) print ("in the test1") @timer def test2(name): # test2 = timer(test2) == deco test2(name) == deco(name) time.sleep(3) print ("in the test2",name) test1() test2("xieshengsen") # in the test1 # the func run time 3.0004942417144775: # in the test2 xieshengsen # the func run time 3.0003535747528076: '''
# eg_v3
# 一個簡單的登陸頁面認證過程(裝飾器)(裝飾函式帶引數)
user = "aaaaaa" pawd = "123456" 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 username == user and password == pawd: print ("login....") res = func(*args,**kwargs) # from home print ("-*-*-*-*-after auth-*-*-*-*-") return res else: print ("invalid...") elif auth_type == "ldap": input("ldap") print ("use ladp auth...") return wrapper return outer_wrapper def index(): print ("welcome to index page.") @auth(auth_type="local") def home(): print("welcome to home age.") @auth(auth_type="ldap") def bbs(): print("welcome to bbs age.") index() home() bbs()
另 一些關於裝飾器介紹的例項
來自:http://blog.csdn.net/yhy1271927580/article/details/72758577
"""
被裝飾的物件為函式,且不帶引數
簡要說明: @timeit裝飾器對sleep函式進行了裝飾,這是一個裝飾器不帶引數的裝飾器,當sleep函式呼叫的時候,呼叫的並不是我們看到的原始的sleep函式,而是裝飾過後的sleep函式。這個裝飾的過程會發生在呼叫sleep函式之前發生。
裝飾的過程:原生的sleep函式作為引數傳遞到timeit裝飾器函式的fn引數,通過@wraps這個裝飾器將fn的屬性賦值給底下需要返回的wrap函式,最後返回wrap函式,由此可間,wrap就是裝飾過後的sleep函式了。那麼在呼叫新sleep函式的時候,就是呼叫wrap函式,sleep函式的引數2,被wrap函式的*args、**kwargs這兩個可變引數接收。
整個裝飾的目的就是將原生的sleep函式,擴充了一個print(nowTime() - start)的過程。
"""
from time import sleep as sleeping from time import time as nowtime from functools import wraps def timeit(fn): @wraps(fn) def wrap(*args,**kwargs): start = nowtime() ret = fn(*args,**kwargs) print (nowtime() - start) return ret return wrap @timeit def sleep(n): sleeping(n) print("sleep time {}s".format(n)) return n sleep(2) print("%s func" % sleep.__name__) # sleep time 2s # 2.0028135776519775 # sleep func
"""
被裝飾的物件為函式,且帶引數
簡要說明: @timeit裝飾器對sleep函式進行了裝飾,這是一個裝飾器是帶引數的裝飾器.
這個裝飾器由於需要傳遞引數,因此需要兩層裝飾,第一層是接受傳遞的參宿,第二層是接收傳遞進來的需要裝飾的函式當sleep函式呼叫的時候,呼叫的並不是我們看到的原始的sleep函式,而是裝飾過後的sleep函式。
裝飾的過程:裝飾器第一次接收cpu_time引數,然後返回一個dec裝飾器,而這個dec裝飾器會被再次呼叫,傳入引數是原生的sleep函式,原生的sleep函式作為引數傳遞到dec裝飾器函式的fn引數,通過@wraps這個裝飾器將fn的屬性賦值給底下需要返回的wrap函式,最後返回wrap函式
在呼叫新sleep函式的時候,就是呼叫wrap函式,sleep函式的引數2,被wrap函式的*args、**kwargs這兩個可變引數接收。整個裝飾的目的就是將原生的sleep函式,擴充了一個time_func = time.clock if cpu_time else time.time和print(nowTime() - start)的過程
"""
from functools import wraps import time def timeit(cpu_time=False): print("timeit") def dec(fn): @wraps(fn) def wrap(*args,**kwargs): start = time.time() ret = fn (*args,**kwargs) print(time.time() - start) return ret return wrap return dec @timeit(False) def sleep(n): time.sleep(n) print ("time sleep") return n sleep(2) print("%s func" % sleep.__name__) # timeit # time sleep # 2.009625196456909 # sleep func