python必學知識之裝飾器詳解
1.函數(shù)引用的概念
理解裝飾器之前先要理解函數(shù)引用的概念
def func():
print("hello world!")
# 調(diào)用函數(shù)
func()
# 引用函數(shù)
ret = func
print(id(ret))
print(id(func))
# 通過引用調(diào)用函數(shù)
ret()運行結果ret和func的id相同,python里一切皆對象,函數(shù)名也是一個對象,ret是func函數(shù)的引用,它也指向func函數(shù)?;蛘呤呛瘮?shù)名僅僅是個變量,只不過指向了定義的函數(shù)而已,所以才能通過 函數(shù)名() 調(diào)用
2.理解閉包的概念
理解:先定義一個函數(shù),然后在該函數(shù)內(nèi)部再定義一個函數(shù),并且這個函數(shù)用到了外邊函數(shù)的變量,那么將這個函數(shù)以及用到的一些變量稱之為閉包
# 定義一個函數(shù)
def func(num1):
# 在函數(shù)內(nèi)部再定義一個函數(shù),并且這個函數(shù)用到了外邊函數(shù)的變量,那么將這個函數(shù)以及用到的一些變量稱之為閉包
def wrapper(num2):
# 在python3中,如果要修改外部函數(shù)的變量,需要加一條申明: nonlocal 外部變量名
# nonlocal num1
# num += 1
print("%s * %s 的積是%s" % (num1, num2, num1 * num2))
return num1 * num2
# 其實這里返回的就是閉包的結果,即返回內(nèi)層函數(shù)的引用
return wrapper
# 給func函數(shù)賦值,這個20就是給參數(shù)num1
ret = func(20) # 等價于ret = wrapper
# 注意這里的100其實給參數(shù)num2
print(ret(100)) # 等同于 print(wrapper(100))運行結果將會顯示 20 * 100 的積是2000 注意點: 由于閉包引用了外部函數(shù)的局部變量,則外部函數(shù)的局部變量沒有及時釋放,消耗內(nèi)存
3.裝飾器
裝飾器是程序開發(fā)中經(jīng)常會用到的一個功能,用好了裝飾器,開發(fā)效率如虎添翼,所以這也是Python面試中必問的問題。 假設下以下場景:
1.公司原本開發(fā)了一套軟件,各個部門一起合作開發(fā),目前公司有條不紊的進行著,但是,以前基礎平臺的開發(fā)人員在寫代碼時候沒有關注驗證相關的問題,即需要增加以下功能:在所有功能執(zhí)行前,先進行權限驗證。
2.老大把工作交給 Low B,他是這么做的: 跟每個業(yè)務部門交涉,每個業(yè)務部門自己寫代碼,調(diào)用基礎平臺的功能之前先驗證。這樣一來基礎平臺就不需要做任何修改了。
太棒了,有充足的時間泡妹子… 當天Low B 被開除了…
3.老大把工作交給 Low BB,他是這么做的:
############### 基礎平臺提供的功能如下 ###############
def f1():
# 驗證1
# 驗證2
# 驗證3
print('f1')
def f2():
# 驗證1
# 驗證2
# 驗證3
print('f2')
def f3():
# 驗證1
# 驗證2
# 驗證3
print('f3')
def f4():
# 驗證1
# 驗證2
# 驗證3
print('f4')
############### 業(yè)務部門不變 ###############
### 業(yè)務部門A 調(diào)用基礎平臺提供的功能###
f1()
f2()
f3()
f4()
### 業(yè)務部門B 調(diào)用基礎平臺提供的功能 ###
f1()
f2()
f3()
f4()
過了一周 Low BB 被開除了…4.老大把工作交給 Low BBB,他是這么做的: 只對基礎平臺的代碼進行重構,其他業(yè)務部門無需做任何修改
############### 基礎平臺提供的功能如下 ###############
def check_login():
# 驗證1
# 驗證2
# 驗證3
pass
def f1():
check_login()
print('f1')
def f2():
check_login()
print('f2')
def f3():
check_login()
print('f3')
def f4():
check_login()
print('f4')老大看了下Low BBB 的實現(xiàn),嘴角漏出了一絲的欣慰的笑,語重心長的跟Low BBB聊了個天:
5.老大說: 寫代碼要遵循開放封閉原則,雖然在這個原則是用的面向?qū)ο箝_發(fā),但是也適用于函數(shù)式編程,簡單來說,它規(guī)定已經(jīng)實現(xiàn)的功能代碼不允許被修改,但可以被擴展,即:
- 封閉:已實現(xiàn)的功能代碼塊
- 開放:對擴展開發(fā)
如果將開放封閉原則應用在上述需求中,那么就不允許在函數(shù) f1 、f2、f3、f4的內(nèi)部進行修改代碼,老板就給了Low BBB一個實現(xiàn)方案:
def w1(func):
def inner():
# 驗證1
# 驗證2
# 驗證3
func()
return inner
@w1
def f1():
print('f1')
@w1
def f2():
print('f2')
@w1
def f3():
print('f3')
@w1
def f4():
print('f4')對于上述代碼,也是僅僅對基礎平臺的代碼進行修改,就可以實現(xiàn)在其他人調(diào)用函數(shù) f1 f2 f3 f4 之前都進行【驗證】操作,并且其他業(yè)務部門無需做任何操作。
4.詳解裝飾器
4.1 裝飾器執(zhí)行流程

4.2 帶多個參數(shù)的裝飾器
例如記錄某個函數(shù)的執(zhí)行時間
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'))4.3 給裝飾器帶參數(shù)
def outer(flag):
def timer(func):
def inner(*args,**kwargs):
if flag:
print('''執(zhí)行函數(shù)之前要做的''')
re = func(*args,**kwargs)
if flag:
print('''執(zhí)行函數(shù)之后要做的''')
return re
return inner
return timer
# 下面的裝飾過程
# 1. 調(diào)用outer(False)
# 2. 將步驟1得到的返回值,即timer返回, 然后timer(func),這里的func指向定義的func函數(shù)
# 3. 將timer(func)的結果返回,即inner
# 4. 讓func = inner,即func現(xiàn)在指向inner
@outer(False)
def func():
print(111)
func()調(diào)用時候的func()可以理解為:func() ====> outer(Flase)(func)()
4.4裝飾器的功能:
在不修改原函數(shù)及其調(diào)用方式的情況下對原函數(shù)功能進行擴展。
4.5.裝飾器應用場景:
(1)引入日志
(2)函數(shù)執(zhí)行時間統(tǒng)計
(3)執(zhí)行函數(shù)前預備處理
(4)執(zhí)行函數(shù)后清理功能
(5)權限校驗等場景
(6)緩存
4.6 functools的應用
正常我們情況下查看函數(shù)的一些信息的方法在此處都會失效
def outer(func):
def inner(*args,**kwargs):
"""hello world"""
return func(*args,**kwargs)
return inner
@outer
def index():
'''你好,世界'''
print('hello world!')
print("函數(shù)注釋:%s" % index.__doc__) #查看函數(shù)注釋的方法
print("函數(shù)名:%s" % index.__name__) #查看函數(shù)名的方法上述代碼返回的結果是:

很顯然,這不是我們需要的結果。我們希望得到的是被裝飾的函數(shù)的函數(shù)名和注釋。
functools的wraps能夠?qū)⒃械暮瘮?shù)名返回,需要使用functools.wraps在裝飾器中的函數(shù)上把傳進來的這個函數(shù)進行一個包裹,這樣就不會丟失原來的函數(shù)的__name__等屬性.
from functools import wraps
def outer(func):
@wraps(func)
def inner(*args,**kwargs):
"""hello world"""
return func(*args,**kwargs)
return inner
@outer
def index():
'''你好,世界'''
print('hello world!')
print("函數(shù)注釋:%s" % index.__doc__) #查看函數(shù)注釋的方法
print("函數(shù)名:%s" % index.__name__) #查看函數(shù)名的方法運行結果為:

5.類裝飾器
class Test(object):
def __init__(self, func):
print("---初始化---")
print("func name is %s"%func.__name__)
self.__func = func
def __call__(self):
print("---裝飾器中的功能---")
self.__func()
#說明:
#1. 當用Test來裝作裝飾器對test函數(shù)進行裝飾的時候,首先會創(chuàng)建Test的實例對象
# 并且會把test這個函數(shù)名當做參數(shù)傳遞到__init__方法中
# 即在__init__方法中的屬性__func指向了test指向的函數(shù)
#
#2. test指向了用Test創(chuàng)建出來的實例對象
#
#3. 當在使用test()進行調(diào)用時,就相當于讓這個對象(),因此會調(diào)用這個對象的__call__方法
#
#4. 為了能夠在__call__方法中調(diào)用原來test指向的函數(shù)體,所以在__init__方法中就需要一個實例屬性來保存這個函數(shù)體的引用
# 所以才有了self.__func = func這句代碼,從而在調(diào)用__call__方法中能夠調(diào)用到test之前的函數(shù)體
@Test
def test():
print("----test---")
test()
showpy()#如果把這句話注釋,重新運行程序,依然會看到"--初始化--"運行結果如下:
---初始化---
func name is test
---裝飾器中的功能---
----test---
到此這篇關于python必學知識之裝飾器詳解的文章就介紹到這了,更多相關python裝飾器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Python爬蟲框架scrapy實現(xiàn)downloader_middleware設置proxy代理功能示例
這篇文章主要介紹了Python爬蟲框架scrapy實現(xiàn)downloader_middleware設置proxy代理功能,結合實例形式分析了scrapy框架proxy代理設置技巧與相關問題注意事項,需要的朋友可以參考下2018-08-08
如何使用Python的Requests包實現(xiàn)模擬登陸
這篇文章主要為大家詳細介紹了使用Python的Requests包模擬登陸,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-04-04
TensorFlow2.0使用keras訓練模型的實現(xiàn)
這篇文章主要介紹了TensorFlow2.0使用keras訓練模型的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-02-02
python解析中國天氣網(wǎng)的天氣數(shù)據(jù)
最近學習python 感覺這門腳本語言十分靈活 而且功能十分強大 尤其是他re庫用于正則匹配十分強大,寫了個例子解析中國天氣網(wǎng)2014-03-03
深度Q網(wǎng)絡DQN(Deep Q-Network)強化學習的原理與實戰(zhàn)
深度Q學習將深度神經(jīng)網(wǎng)絡與強化學習相結合,解決了傳統(tǒng)Q學習在高維狀態(tài)空間下的局限性,通過經(jīng)驗回放和目標網(wǎng)絡等技術,DQN能夠在復雜環(huán)境中學習有效的策略,本文通過CartPole環(huán)境的完整實現(xiàn),展示了DQN的核心思想和實現(xiàn)細節(jié)2025-04-04
python超詳細實現(xiàn)完整學生成績管理系統(tǒng)
讀萬卷書不如行萬里路,只學書上的理論是遠遠不夠的,只有在實戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用Java實現(xiàn)一個完整版學生成績管理系統(tǒng),大家可以在過程中查缺補漏,提升水平2022-03-03

