Python的裝飾器
阿新 • • 發佈:2020-12-28
文章目錄
Python中裝飾器的使用
在軟體開發過程中,不同的階段設計開發時會定義一些函式,而後期的開發過程中,希望擴充套件一些裝飾這個函式的內容,即裝飾器;舉例如下
存在一個計算兩個數相加的函式
def add(a , b):
'''
求任意兩個數的和
'''
r = a + b
return r
res = add(123,456)
print(res)
執行結果:
579
希望在執行這個計算前程式輸出"計算開始…";計算時輸出"計算結束…" 前提是不能改變原函式;如下所示
#定義一個函式,達到需求的設計
def new_add(a,b):
print('計算開始~~~')
r = add(a,b)
print('計算結束~~~')
return r
r = new_add(111,456)
print(r)
執行結果
計算開始~~~
計算結束~~~
567
以上的設計雖然完成了需求,但是相對應的也帶來了一些問題
-
如果要修改的函式過多,修改起來會比較麻煩
-
並且不方便後期的維護
-
並且這樣做會違反開閉原則(OCP)
OCP: Open Control Principle 程式的設計,要求開放對程式的擴充套件,要關閉對程式的修改
為了解決這個問題,建立一個可以自動的生產函式
裝飾器的定義
# 用於計算兩個數相加
def add(a,b):
r = a+b
return r
# 用於計算兩個數相乘
def mul(a,b):
r = a*b
return r
def decorators(fun):
'''
這是一個裝飾器函式
用來對其他函式進行擴充套件,使其他函式可以在執行前列印開始執行,執行後列印執行結束
引數:
fun 要擴充套件的函式物件
'''
# 建立一個新函式
'''
*args 用於接收所有的位置引數
**kwargs 用於接受所有的關鍵字引數
'''
def new_fun(*args,**kwargs): #將引數裝包成元組或字典
print('計算開始...')
# 呼叫被擴充套件的函式
num = fun(*args,**kwargs) #將元組拆包成位置引數,將字典拆包成關鍵字引數
print('計算結束...')
# 返回函式的執行結果
return num
# 返回新函式
return new_fun
# 呼叫
r = decorators(add) # 將裝飾器函式的返回值函式,即內部的函式給到r
print(r) # r就是裝飾器函式的內部函式的記憶體地址
res = r(123,456) # 向內部函式傳參,相當於add(123,456)
print(res)
執行結果
<function decorators.<locals>.new_fun at 0x0000016AFFFB6950>
計算開始...
計算結束...
579
計算兩個數相乘的情況,如下呼叫
r = decorators(add)
print(r)
res = r(123,456)
print(res)
print('-'*30)
r = decorators(mul)
print(r)
res = r(2,3)
print(res)
執行結果
<function decorators.<locals>.new_fun at 0x000001D00B7168C8>
計算開始...
計算結束...
579
------------------------------
<function decorators.<locals>.new_fun at 0x000001D00B716950>
計算開始...
計算結束...
6
可見,每次呼叫裝飾器函式的內部函式時,分配的記憶體肯定是不一樣的,傳入的add、mul實參
就是真實計算的函式內容
裝飾器的使用
- 通過裝飾器,可以在不修改原來函式的情況下來對函式進行擴充套件
- 在開發中,我們都是通過裝飾器來擴充套件函式的功能的
- 在定義函式時,可以通過@裝飾器,來使用指定的裝飾器,來裝飾當前的函式
如下所示:函式裝飾器的內容不變,只是在定義函式的時候加上@裝飾器函式的名稱
即可
但是這樣一來,裝飾器就與函式實體進行了繫結,以後呼叫函式時都會攜帶裝飾器
def decorators(fun):
'''
這是一個裝飾器
用來對其他函式進行擴充套件,使其他函式可以在執行前列印開始執行,執行後列印執行結束
引數:
fun 要擴充套件的函式物件
'''
# 建立一個新函式
'''
*args 用於接收所有的位置引數
**kwargs 用於接受所有的關鍵字引數
'''
def new_fun(*args,**kwargs): #將引數裝包成元組或字典
print('計算開始...')
# 呼叫被擴充套件的函式
num = fun(*args,**kwargs) #將元組拆包成位置引數,將字典拆包成關鍵字引數
print('計算結束...')
# 返回函式的執行結果
return num
# 返回新函式
return new_fun
# 對函式實體進行裝飾
@decorators
def add(a,b):
r = a+b
return r
@decorators
def mul(a,b):
r = a*b
return r
# 呼叫
res = add(123,456)
print(res)
print('-'*30)
res = r(2,3)
print(res)
計算開始...
計算結束...
579
------------------------------
計算開始...
計算結束...
6
多個裝飾器的呼叫
- 可以同時為一個函式指定多個裝飾器
- 函式將會安裝從內向外的順序被裝飾
def fn1(fun):
def new_function(*args , **kwargs):
print('fn1裝飾~開始執行~~~~')
result = fun(*args , **kwargs)
print('fn1裝飾~執行結束~~~~')
return result
return new_function
def fn2(fun):
def new_function(*args , **kwargs):
print('fn2裝飾~開始執行~~~~')
result = fun(*args , **kwargs)
print('fn2裝飾~執行結束~~~~')
return result
return new_function
@fn1
@fn2
def say_hello():
print('大家好~~~')
say_hello()
由內到外的執行就是,以say_hello()函式的輸出結果為中心,先使用fn2裝飾器,然後使用fn1裝飾器
執行結果
fn1裝飾~開始執行~~~~
fn2裝飾~開始執行~~~~
大家好~~~
fn2裝飾~執行結束~~~~
fn1裝飾~執行結束~~~~
改變順序
@fn2
@fn2
def say_hello():
print('大家好~~~')
say_hello()
執行結果
fn2裝飾~開始執行~~~~
fn1裝飾~開始執行~~~~
大家好~~~
fn1裝飾~執行結束~~~~
fn2裝飾~執行結束~~~~