便捷語符不代表他很便捷,(就跟老婆餅沒老婆一樣)。
它可透過一些特殊語符(符號+方法),達到某些功能。這往往會在不影響程式整體結構下來增加一些功能,其實就是AOP(剖面導向)的核心觀念。
之前介紹各種程式設計法時有談到 AOP是抽象的,而且理解它是有難度的,所以稍微感覺
一下它就好了。
OOP的物件都是寫在代碼裡的,可以提高程式的穩定性。但AOP強調是插入或增加一些功能與語法,並且不改變原本的結構。
AOP用在測試 , 外部深入處理 , 寫入日誌檔 , 監控(包含HIPS入侵防禦系統),有很大幫助。
有人會把他歸類為函式設計的一部份,但它還是進入AOP前會用到的觀念。
這就需透過裝飾器@的用法了,有時函式調用不能改變其結構。因為其他物件也要調用同方法,這時"@"就相當方便了。它也是種語法糖,所以不影響原語法
有兩函式或class a 跟 b 並且a(b) 繼承
所以@a 就是 b = a(b)
@a要寫在兩物件中間,但a(b)要寫後面。這就產生了功能差別
import time
def timeit(foo):
def fc():
start = time.clock()
a = int(input('range?'))
foo(a) #插入功能
end =time.clock()
print('used:' , end-start)
return fc
@timeit
def foo(a):
for i in range(0,a):
i+=1
print('%d range' %i)
timeit(foo())
有發現嗎?這樣隨時變更foo(a)功能就不會跟其他方法衝突了
這兩個可通稱為靜態類別,都是為了定義方法給物件以便於使用。
self:專門用在OOP,會被__init__先調用
cls :專門用在AOP,會被class先調用
來看以下內建裝飾器與cls的用法:
class AR(object):
@staticmethod #不須再把類別物件化:AR=AR()
def a(): #包含靜態類別
print('fc_a')
@classmethod #不須再把類別物件化:AR=AR()
def wd(cls): #須有靜態類別 cls
return ('fc_wd')
AR.a()
AR.wd()
這語法糖可謂二度減化語法,達到簡潔的特性。
這裡的cls是為class提拱參考屬性用的,這樣才可直接當成物件調用
@為何可代替 b = b(a) 呢?那是因為它的靈活性:
def M(name):
def M_ins(func):
def M_fc1(*args):
print(name)
print("i'm M_fc1 empty")
a = func(*args)
print("i'm M_fc1 fc")
return a
return M_fc1
return M_ins
#可延續 可改值
@M('dc1')
def dc1(name):
print(name)
return None
@M('dc2')
def dc2(name):
print(name)
return None
dc1('name1')
dc2('name2')
以前可能需透過OOP的多重繼承才能做到的複雜調用,現在透過裝飾器也能做到這點。
而它也可以疊加方法,但為了避免改變方法。需額外做個為裝飾器調用之物件,這樣才不會影響主結構
就算沒做額外物件,裝飾器也會避免方法影響程式結構。所以可透過特性來檢查裝飾器是否可工作。
def fc1(func):
def infc(r):
print('fc1')
r = func(r) # 避免影響功能的調用
return r
return infc
def fc2(func):
def infc(r):
print('fc2')
r = func(r) # 避免影響功能的調用
return r
return infc
def fc3(func):
def infc(r):
print('fc3')
r = func(r) # 避免影響功能的調用
return r
return infc
#test = fc1(fc2(fc3(test)))
@fc1
@fc2
@fc3
def test(name):
print(name)
test('test')