楔子
作為一個會寫函式的python開發,我們從今天開始要去公司上班了,寫了一個函式,就交給其他開發用了,
def func1():
print('in func1')
季度末,公司的領導要給大家發績效獎金了,就提議對這段日子所有人開發的成果進行審核,審核的標準是什么呢?就是統計每個函式的執行時間,
這個時候你要怎么做呀?
你一想,這好辦,把函式一改:
import time
def func1():
start = time.time()
print('in func1')
print(time.time() - start)
func1()
來公司半年,寫了2000+函式,挨個改一遍,1個禮拜過去了,等領導審核完,再挨個給刪了,,,又1個禮拜過去了,,,這是不是很鬧心?
你覺得不行,不能讓自己費勁兒,告訴所有開發,現在你們都在自己原本的代碼上加上一句計算時間的陳述句?
import time
def func1():
print('in func1')
start = time.time()
func1()
print(time.time() - start)
還是不行,因為這樣對于開發同事來講實在是太麻煩了,
那怎么辦呢?你靈機一動,寫了一個timer函式,,,
import time
def timer(func):
start = time.time()
func()
print(time.time() - start)
def func1():
print('in func1')
def func2():
print('in func2')
timer(func1)
timer(func2)
這樣看起來是不是簡單多啦?不管我們寫了多少個函式都可以呼叫這個計時函式來計算函式的執行時間了,,,盡管現在修改成本已經變得很小很小了,但是對于同事來說還是改變了這個函式的呼叫方式,假如某同事因為相信你,在他的代碼里用你的方法用了2w多次,那他修改完代碼你們友誼的小船也就徹底地翻了,
你要做的就是,讓你的同事依然呼叫func1,但是能實作呼叫timer方法的效果,
import time
def timer(func):
start = time.time()
func()
print(time.time() - start)
def func1():
print('in func1')
func1 =timer #要是能這樣的就完美了,,,可惜報錯
func1()
非常可惜,上面這段代碼是會報錯的,因為timer方法需要傳遞一個func引數,我們不能在賦值的時候傳參,因為只要執行func1 = timer(func1),timer方法就直接執行了,下面的那句func1根本就沒有意義,到這里,我們的思路好像陷入了僵局,,,
裝飾器的形成程序
裝飾器——簡單版
import time
def func1():
print('in func1')
def timer(func):
def inner():
start = time.time()
func()
print(time.time() - start)
return inner
func1 = timer(func1)
func1()
忙活了這么半天,終于初具規模了!現在已經基本上完美了,唯一礙眼的那句話就是還要在做一次賦值呼叫,,,
你覺得礙眼,python的開發者也覺得礙眼,所以就為我們提供了一句語法糖來解決這個問題!
裝飾器——語法糖
import time
def timer(func):
def inner():
start = time.time()
func()
print(time.time() - start)
return inner
@timer #==> func1 = timer(func1)
def func1():
print('in func1')
func1()
到這里,我們可以簡單的總結一下:
裝飾器的本質:一個閉包函式
裝飾器的功能:在不修改原函式及其呼叫方式的情況下對原函式功能進行擴展
還有最后一個問題要解決,剛剛我們討論的裝飾器都是裝飾不帶引數的函式,現在要裝飾一個帶引數的函式怎么辦呢?
裝飾器——帶引數的裝飾器
def timer(func):
def inner(a):
start = time.time()
func(a)
print(time.time() - start)
return inner
@timer
def func1(a):
print(a)
func1(1)
其實裝飾帶參的函式并不是什么難事,但假如你有兩個函式,需要傳遞的引數不一樣呢?
裝飾器——萬能傳參
import time
def timer(func):
def inner(*args,**kwargs):
start = time.time()
re = func(*args,**kwargs)
print(time.time() - start)
return re
return inner
@timer #==> func1 = timer(func1)
def func1(a,b):
print('in func1')
@timer #==> func2 = timer(func2)
def func2(a):
print('in func2 and get a:%s'%(a))
return 'fun2 over'
func1('aaaaaa','bbbbbb')
print(func2('aaaaaa'))
現在引數的問題已經完美的解決了,可是如果你的函式是有回傳值的呢?
裝飾器——帶回傳值的裝飾器
import time
def timer(func):
def inner(*args,**kwargs):
start = time.time()
re = func(*args,**kwargs)
print(time.time() - start)
return re
return inner
@timer #==> func2 = timer(func2)
def func2(a):
print('in func2 and get a:%s'%(a))
return 'fun2 over'
func2('aaaaaa')
print(func2('aaaaaa'))
剛剛那個裝飾器已經非常完美了,但是正常我們情況下查看函式的一些資訊的方法在此處都會失效
查看函式資訊的方法
def index():
'''這是一個主頁資訊'''
print('from index')
print(index.__doc__) #查看函式注釋的方法
print(index.__name__) #查看函式名的方法
為了不讓他們失效,我們還要在裝飾器上加上一點來完善它:
裝飾器——warps demo
from functools import wraps
def deco(func):
@wraps(func) #加在最內層函式正上方
def wrapper(*args,**kwargs):
return func(*args,**kwargs)
return wrapper
@deco
def index():
'''哈哈哈哈'''
print('from index')
print(index.__doc__)
print(index.__name__)
開放封閉原則
1.對擴展是開放的
為什么要對擴展開放呢?
我們說,任何一個程式,不可能在設計之初就已經想好了所有的功能并且未來不做任何更新和修改,所以我們必須允許代碼擴展、添加新功能,
2.對修改是封閉的
為什么要對修改封閉呢?
就像我們剛剛提到的,因為我們寫的一個函式,很有可能已經交付給其他人使用了,如果這個時候我們對其進行了修改,很有可能影響其他已經在使用該函式的用戶,
裝飾器完美的遵循了這個開放封閉原則,
裝飾器的主要功能和裝飾器的固定結構
裝飾器的主要功能
在不改變函式呼叫方式的基礎上在函式的前、后添加功能,
裝飾器的固定格式
def timer(func):
def inner(*args,**kwargs):
'''執行函式之前要做的'''
re = func(*args,**kwargs)
'''執行函式之后要做的'''
return re
return inner
# wraps
from functools import wraps
def deco(func):
@wraps(func) #加在最內層函式正上方
def wrapper(*args,**kwargs):
return func(*args,**kwargs)
return wrapper
帶引數的裝飾器
假如你有成千上萬個函式使用了一個裝飾器,現在你想把這些裝飾器都取消掉,你要怎么做?
一個一個的取消掉? 沒日沒夜忙活3天,,,
過兩天你領導想通了,再讓你加上,,,
def outer(flag):
def timer(func):
def inner(*args,**kwargs):
if flag:
print('''執行函式之前要做的''')
re = func(*args,**kwargs)
if flag:
print('''執行函式之后要做的''')
return re
return inner
return timer
@outer(False)
def func():
print(111)
func()
多個裝飾器裝飾同一個函式
有些時候,我們也會用到多個裝飾器裝飾同一個函式的情況,
def wrapper1(func):
def inner():
print('wrapper1 ,before func')
func()
print('wrapper1 ,after func')
return inner
def wrapper2(func):
def inner():
print('wrapper2 ,before func')
func()
print('wrapper2 ,after func')
return inner
@wrapper2
@wrapper1
def f():
print('in f')
f()
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/194764.html
標籤:Python
上一篇:Python_函式進階
下一篇:Python_迭代器和生成器
