由於有時候一天看的內容比較多,寫在一章比較亂而且後期不好找,寫多章一天發了好幾天不太真實,所以天改爲章
2019/11/6 沒有暖氣凍死了快
軟件設計原則之一 —> 開閉原則
對功能的擴展開放:可以隨意增加或者減少功能
但是,可以加功能,但是不能也不需要修改源代碼,這樣子纔是最穩定的
對代碼修改是封閉的
裝飾器
先來個小故事,女媧造人
def zaoren():
print("捏個泥人")
print("吹口仙氣")
print("你就出來了")
zaoren()
zaoren()
zaoren()
每造一個人,就調用一次函數,就可以了
但是,之前可以這麼做,現在來了三年大旱,沒有水了,也就沒有了泥,現在造人之前要先和泥.
但是現在大旱需要水和泥,但是過幾天可能就下雨,不需要了和泥.
這個時候就可以選擇用裝飾器,因爲有個功能有時需要又是不需要.
def water():
print("和泥")
zaoren()
這個時候可以寫成這樣子,等到不需要這個功能,還是可以直接調用zaoren()函數.
但是,之前的zaoren函數都需要改成water,工程量很大.所以此時需要裝飾器.
裝飾器雛形
def zhuangshi(fn): #傳遞進一個函數
def haha():
print("和泥")
fn() #調用這個函數
return haha
def zaoren():
print("捏個泥人")
print("吹口仙氣")
print("你就出來了")
#qwe = zhuangshi(zaoren) #前面接受的就是一個變量,但是這樣子調用還是和之前zaoren不同了,所以改成zoaren
zaoren = zhuangshi(zaoren)
zaoren() #輸出:和泥 \n捏個泥人 \n 吹口仙氣 \n 你就出來了
#qwe = zhuangshi(zaoren) #前面接受的就是一個變量,但是這樣子調用還是和之前zaoren不同了,所以改成zoaren
zaoren = zhuangshi(zaoren)
zaoren() #輸出:和泥 \n捏個泥人 \n 吹口仙氣 \n 你就出來了
#但是,不只有造人需要和泥,蓋房子也需要.那麼
def jian():
print("蓋房子")
jian = zhuangshi(jian)
jian() #輸出:和泥 \n 蓋房子
#此時,所有和和泥相關操作都可以調用,並且可以再之前或者之後添加功能.
def game():
print("打開GAT")
print("搶一架飛機")
print("跟警察死磕")
#現在遊戲前想開掛
def gua(play):
def wai():
print("打開外掛")
play()
print("關閉外掛")
return wai
game = gua(game)
game() #輸出:打開外掛 \n 打開GAT \n 搶一架飛機 \n 跟警察死磕 \n 關閉外掛
# 此時,還可以適用別的
def cf():
print("打開CF")
print("殺人")
print("勝利")
cf = gua(cf)
cf() #輸出: 打開外掛 \n 打開CF \n 殺人 \n 勝利 \n 關閉外掛
def game(username,password):
print("打開CF")
print("登陸",username,password)
print("殺人")
print("勝利")
#現在調用需要傳遞參數
def gua(en):
def haha(username,password):
print("開掛")
en(username,password)
return haha
game = gua(game)
game("liulaoliu",123) # 輸出:開掛 打開CF 登陸 liulaoliu 123 殺人 勝利
#但是現在想玩其他的GTA,GTA不需要QQ登陸,只需要一個用戶名
def game(username):
print("打開GAT")
print("用戶名",username)
print("搶一架飛機")
print("跟警察死磕")
#裝飾器改爲:
def gua(en):
def haha(*username,**password):
print("開掛")
en(*username,**password)
return haha
#這樣子就可以只傳遞一個參數
game = gua(game)
game("wulaowu")
# 輸出:開掛 打開GAT 用戶名 wulaowu 搶一架飛機 跟警察死磕
def game(username,password):
print("打開GAT")
print("用戶名",username,password)
print("搶一架飛機")
print("跟警察死磕")
return ("十萬金幣")
qwe = game(111,222)
print(qwe) # 此處調用函數會到一個return的返回值 "十萬金幣"
def gua(en):
def haha(*username,**password):
print("開掛")
en(*username,**password) #此處改寫爲以下兩行,接收函數的返回值,就不會輸出None了.
#qwe = en(*username,**password) #函數在此處進行裝飾調用的時候沒有接收返回值,所以輸出None,改寫爲這樣子接收返回值
#return qwe #並且在此處進行了返回,函數正常調用
return haha
game = gua(game)
wer = game("123",456)
print(wer) #但是現在經過裝飾器之後沒有了返回值 ,只有一個None
通用裝飾器語法!
# 存在意義: 在不破壞原來函數的前提下,給原來代碼插入一些新的功能
#Python中的動態代理
def func(fn):
def inner(*args,**kwargs):
'''執行目標函數之前要進行的操作'''
ret = fn(*args,**kwargs)
'''在進行目標函數之後要進行的操作'''
return ret
return inner
@func #這裏就相當於:target_func = func(target_func)
def target_func():
pass
target_func() #此時執行的是inner
帶有參數的裝飾器
def wrapper(fn):
def inner(*args,**kwargs):
print("問問金老闆行情,怎麼樣啊")
ret = fn(*args,**kwargs)
print("金老闆騙我,恨你")
return ret
return inner
@wrapper
def yue():
print("走啊,約嗎")
yue()
# 但是現在有的時候需要問,有的時候不需要問.此時,寫爲
def wrapper_out(flag):
def wrapper(fn):
def inner(*args,**kwargs):
if flag == True:
print("問問金老闆行情,怎麼樣啊")
ret = fn(*args,**kwargs)
print("金老闆騙我,恨你")
return ret
else:
ret = fn(*args, **kwargs)
return ret
return inner
return wrapper
@wrapper_out(True) #先執行wrapper_out,返回wrapper 可以填寫True或者False來控制函數調用
#wrapper_out只是判斷,實際調用韓式wrapper
def yue():
print("走啊,約嗎")
yue()
多個裝飾器裝飾同一個函數,會就近原則,先從函數最近的函數開始依次裝飾,不論先後.