python:從入門到放棄 10 裝飾器
阿新 • • 發佈:2022-03-18
目錄
裝飾器簡介
裝飾器的本質:在不改變被裝飾物件原有的呼叫方式
和內部程式碼
、的情況下給被裝飾物件新增新的功能
軟體的設計應該遵循開放封閉原則,即對擴充套件是開放
的,而對修改是封閉
的。
軟體包含的所有功能的原始碼以及呼叫方式,都應該避免修改,否則一旦改錯,則極有可能產生連鎖反應,最終導致程式崩潰,而對於上線後的軟體,新需求或者變化又層出不窮,我們必須為程式提供擴充套件的可能性,這就用到了裝飾器。
裝飾器
# 首先定義一個函式 def foo(): print("foo") # 如果我們需要修改它的功能 def foo(): print("記錄日誌開始") print("foo") print("記錄日誌結束") '''可以看見的是,我們修改了他的內部程式碼,這有可能導致程式崩潰''' # 使用裝飾器修改函式的功能 def outer(func): # 裝飾器 def inner(): print("記錄日誌開始") func() # 業務函式 print("記錄日誌結束") return inner def foo(): print("foo") # foo函式的內部程式碼沒有被修改 foo = outer(foo) foo() # foo函式的呼叫方法沒有被修改 '''outer 函式的返回值是 inner 函式,在 inner 函式中,除了執行日誌操作,還有業務程式碼,該函式重新賦值給 foo 變數後,呼叫 foo() 就相當於呼叫 inner()''' '''可以看見的是,outer函式就是一個裝飾器,即裝飾器是一個帶有函式作為引數並返回一個新函式的閉包'''
裝飾器模板
'''編寫裝飾器其實有一套固定的程式碼 不需要做任何理解'''
def outer(func_name): # func_name用於接收被裝飾的物件(函式)
def inner(*args, **kwargs):
print('執行被裝飾函式之前 可以做的額外操作')
res = func_name(*args, **kwargs) # 執行真正的被裝飾函式
print('執行被裝飾函式之後 可以做的額外操作')
return res # 返回真正函式的返回值
return inner
語法糖
# 僅僅是讓程式碼編寫的更加好看、簡潔!!!
@outer # foo = outer(foo) 省去了手動給foo重新賦值的步驟。
def foo():
print("foo")
foo()
'''語法糖內部原理
1.使用的時候最好緊跟在被裝飾物件的上方
2.語法糖會自動將下面緊挨著的函式名傳給@後面的函式呼叫'''
裝飾器修復技術
Python裝飾器在實現的時候,被裝飾後的函式其實已經是另外一個函數了(函式名等函式屬性會發生改變),而python的functools包中提供了一個叫wraps的裝飾器來消除這樣的副作用。它能保留原有函式的名稱和註釋。
from functools import wraps def outer(func_name): @wraps(func_name) # 使用wraps裝飾器 def inner(*args, **kwargs): '''這是inner函式的註釋''' print('執行被裝飾物件之前可以做的操作') res = func_name(*args, **kwargs) return res return inner @outer def index(): print('from index') @outer def home(): '''這是home函式的註釋''' print('from home') help(home) # home() 輸出的是home的函式名 # 這是home函式的註釋 輸出的是home的註釋
如果我們將wraps裝飾器註釋
# from functools import wraps
def outer(func_name):
# @wraps(func_name) # 不使用wraps裝飾器
def inner(*args, **kwargs):
'''這是inner函式的註釋'''
print('執行被裝飾物件之前可以做的操作')
res = func_name(*args, **kwargs)
return res
return inner
@outer
def index():
print('from index')
@outer
def home():
'''這是home函式的註釋'''
print('from home')
help(home)
# inner(*args, **kwargs) 輸出的是inner的函式名
# 這是inner函式的註釋 輸出的是inner的註釋