堅持原創輸出,點擊藍字關注我吧
做者:清菡
博客:oschina、雲+社區、知乎等各大平臺都有。python
❝因爲微信公衆號推送改成了信息流的形式,防止走丟,請給加個星標 ⭐,你就能夠第一時間接收到本公衆號的推送!web
❞
目錄
-
1、什麼是裝飾器 -
1.開放封閉原則(面向對象原則的核心) -
2.裝飾器的做用 -
2、實現一個裝飾器 -
1.不帶參數的裝飾器 -
2.裝飾器的原理 -
3.組裝方便,拆卸也方便 -
4.帶參數的裝飾器 -
3、通用裝飾器 -
4、裝飾器裝飾類 -
1.不帶參數的 -
2.帶參數的 -
5、裝飾器的應用場景 -
6、補充 -
1.*號的做用 -
2.裝飾器裝飾類和裝飾函數的不一樣點
1、什麼是裝飾器
1.開放封閉原則(面向對象原則的核心)
「對已經實現的功能(項目已經上線了),在這個基礎上增長新功能,也能夠在它的基礎上進行拓展,這個就是開放。若是你要去再修改它內部的代碼,這個時候是不容許的,對內部的修改是封閉的。」微信
就是你實現的功能能夠拓展,可是你不要去修改它內部的代碼。閉包
好比index()
是接口,返回是「這個是網站的首頁」,只要調用這個接口就會返回一個「這個是網站的首頁。」編輯器
忽然有個需求,在進入網站以前須要先登陸校驗一下。這個時候須要拓展,如何拓展?就須要用裝飾器了。
函數
def index():
print("這個是網站的首頁")
這個已經實現的接口,不能去修改的。測試
2.裝飾器的做用
「裝飾器可在不更改這個函數裏面任何代碼的基礎上,給它添加新的功能。」flex
2、實現一個裝飾器
1.不帶參數的裝飾器
裝飾器其實就是一種閉包的應用。要使用裝飾器,能夠先定義個閉包函數。把登陸校驗的功能寫在了閉包函數的內部。網站
把閉包函數當成裝飾器來用的話,外面接收的參數須要傳一個函數,你要裝飾哪一個函數,你就傳哪一個函數。url
# 開放封閉原則
def login(func):
def fun():
# 簡單的校驗
username = 'python01'
password = 'qinghan'
user = input("請輸入帳號:")
pw = input("請輸入密碼:")
# 判斷下帳號密碼對不對
if username == user and pw == password:
func() # 登陸得帳號密碼都正確的狀況下,調用這個函數
else:
print("帳號或密碼錯誤")
return fun
@login # 艾特一下這個裝飾器
def index():
print("這個是網站的首頁")
index()
2.裝飾器的原理
「將被裝飾的函數看成一個參數傳到裝飾器中,而且讓被裝飾的函數名指向裝飾器內部的函數,在裝飾器的內部函數中用接收到的參數再調用被裝飾的函數。」
@login
是 Python 中的一個語法糖。它的做用是:index=login(index)
。傳入index
,而後被index
接收。
如何作到經過func()調用原函數?
@login
等於index=login(index)
。
自動將index
看成參數傳入login
這個函數裏面,去執行login(func)
這個函數,檢測到這個fun()
函數,將這段代碼:
def fun():
# 簡單的校驗
username = 'python01'
password = 'qinghan'
user = input("請輸入帳號:")
pw = input("請輸入密碼:")
# 判斷下帳號密碼對不對
if username == user and pw == password:
func() # 登陸得帳號密碼都正確的狀況下,調用這個函數
else:
print("帳號或密碼錯誤")
直接跳過。
return fun
直接將結果返回出來。結果返回出來又給index()
接收,調用index()
的時候其實是調用fun()
函數。
執行fun()
函數裏面的代碼。經過func()
調用原函數,怎麼作到的?
fun()
函數是放在index.__closure__
這個屬性裏面。
而後在下面調用func()
的時候,就是去index.__closure__
這個屬性裏面找到對應存儲的那塊代碼。
存儲的代碼就是這個:
def index():
print("這個是網站的首頁")
以上,就是裝飾器裝飾的流程。
3.組裝方便,拆卸也方便
我想改爲不用登陸也能夠訪問,直接去掉@login
這個裝飾器就能夠了。
# 開放封閉原則
def login(func):
def fun():
# 簡單的校驗
username = 'python01'
password = 'qinghan'
user = input("請輸入帳號:")
pw = input("請輸入密碼:")
# 判斷下帳號密碼對不對
if username == user and pw == password:
func() # 登陸得帳號密碼都正確的狀況下,調用這個函數
else:
print("帳號或密碼錯誤")
return fun
# @login # 艾特一下這個裝飾器
def index():
print("這個是網站的首頁")
# index.__closure__
index()
這樣操做,不會對原來有什麼影響。
4.帶參數的裝飾器
實現兩個數相加後,又有新的需求,須要能夠相乘、相除。
def add(func):
def fun(a, b):
print("相乘", a * b)
print("相除", a / b)
func(a, b)
return fun
@add
def add_num(a, b):
# 打印兩個數相加
print("相加:", a + b)
add_num(11, 22)
3、通用裝飾器
若是同一個裝飾器既要裝飾有參數的函數,又要裝飾無參數的函數。
那麼咱們在傳參的時候就設置成不定長參數,這樣無論被裝飾的函數有沒有參數都能用。
# 通用裝飾器
def add(func):
def fun(*args, **kwargs):
print("裝飾器的功能代碼:登陸")
func(*args,**kwargs)
return fun
@add
def index():
print("這個是網站的首頁")
@add
def good_list(num):
print("這個是商品列表第{}頁".format(num))
index()
print("------------")
good_list(9)
4、裝飾器裝飾類
1.不帶參數的
#裝飾器裝飾類
def add(func):
def fun(*args, **kwargs):
print("裝飾器的功能代碼:登陸")
return func(*args,**kwargs)
return fun
@add # MyClass=add(MyClass)
class MyClass:
def __init__(self):
pass
m = MyClass()
print("m的值:",m)
把類看成一個參數傳到裝飾器裏面。return fun
返回的是fun
,MyClass
接收到的是fun
。
MyClass()
調用的是fun
。
執行代碼:
def fun(*args, **kwargs):
print("裝飾器的功能代碼:登陸")
return func(*args,**kwargs)
這裏面的功能。
先執行裝飾器的功能,return func(*args,**kwargs)
,func()
來自def add(func)
。
調用MyClass
這個類,return func(*args,**kwargs)
建立了個對象,MyClass()
調用完了接收,m 就能接收這個對象了。
這個就是裝飾器裝飾類的一個原理。
2.帶參數的
#裝飾器裝飾類
def add(func):
def fun(*args, **kwargs):
print("裝飾器的功能代碼:登陸")
return func(*args,**kwargs)
return fun
@add # MyClass=add(MyClass)
class MyClass:
def __init__(self,name,age):
self.name=name
self.age=age
m = MyClass("qinghan","18")
print("m的值:",m)
這裏用的是不定行參數,因此無論你裝飾的類是有參數的仍是沒參數的,均可以。
5、裝飾器的應用場景
1.登陸校驗。(在裝飾器裏面判斷下你有沒有登陸)
2.函數運行時間統計。
3.執行函數以前作準備工做。
4.執行函數後清理功能。
6、補充
1.*號的做用
*
是進行拆包做用的。把每一個元素拿出來,看成參數進行傳遞。
一個*
是對元組形式的位置參數進行拆包,兩個**
對關鍵字參數進行拆包。
2.裝飾器裝飾類和裝飾函數的不一樣點
類須要把對象返回出來。
公衆號「清菡軟件測試」首發,更多原創文章:清菡軟件測試 116+原創文章,歡迎關注、交流,禁止第三方擅自轉載。
感謝關注清菡,歡迎點擊在看和轉發!
本文分享自微信公衆號 - 清菡軟件測試(qinghanTester)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。