Python裝飾器模式學習總結
阿新 • • 發佈:2018-12-03
裝飾器模式,重點在於裝飾。裝飾的核心仍舊是被裝飾物件。
類比於Java程式設計的時候的包裝模式,是同樣的道理。雖然概念上稍有不同但是原理上還是比較相近的。下面我就來談一談我對Python的裝飾器的學習的一點心得吧。
關於作用域
Python作用域 體現在LEGB中:
- L:local 函式內部
- E: enclosing 函式內部和內建函式之間
- G:global 全域性性質,有名稱空間的限制
- B:build-in 內建函式,由python直譯器管理
學過程式設計的人一眼就可以看得出來大致是什麼意思,所以這裡不再敘述。
關於閉包
關鍵在於理解Python中閉包的概念。說白了,閉包就是函式裡面又定義了函式,這就是閉包了。(呵呵,斷章取義一下。可能說法不恰當)。如下:
def func1():
print 'func1 is running'
def in_func1():
print 'in_func1 is running'
return in_func1
print 'over'
簡單的一個閉包的實現,就差不多是這個樣子的。我們需要注意的就是要將內部函式當成一個物件來返回(Python中函式其實就是一個物件,我們可以通過type來進行驗證)。
這段程式碼執行的流程是先執行func1,然後執行func2,並且將func2作為一個屬性返回給func1.這樣我們可以再次的得到func2的內容。這就是閉包!
關於裝飾器
類比Java中那麼多的模式,比如ServletRequest被裝飾成了HttpServletRequest。Python中也有很多這樣被裝飾的例子。如CookieJar被裝飾成了MozillaCookieJar等等。實現的功能就是被裝飾物件的功能得到了增強,完成的效果也大大大的比未裝飾之前好了。這就是裝飾的好處。
下面就來看一看Python中怎麼來實現裝飾器吧。
核心:藉助於@符號,即可。
def bar(func): print 'Bar' return func @bar def foo(): print "foo" # 其等價於: def foo(): print "foo" foo = bar(foo)
程式碼執行的流程:
先執行@物件,也就是一個函式。其返回值就是一個內建函式,只不過這個內建函式是得到了裝飾的被裝飾物件(這裡是foo函式),我們可以理解為:
裝飾器,其本身接收一個函式物件作為引數,然後做一些工作後,返回接收的引數,供外界呼叫。
下面看一個例項:
import time
def function_performance_statistics(trace_this=True):
if trace_this:
def performace_statistics_delegate(func):
def counter(*args, **kwargs):
start = time.clock()
func(*args, **kwargs)
end =time.clock()
print 'used time: %d' % (end - start, )
return counter
else:
def performace_statistics_delegate(func):
return func
return performace_statistics_delegate
@function_performance_statistics(True)
def add(x, y):
time.sleep(3)
print 'add result: %d' % (x + y,)
@function_performance_statistics(False)
def mul(x, y=1):
print 'mul result: %d' % (x * y,)
add(1, 1)
mul(10)
上述程式碼想要實現一個性能分析器,並接收一個引數,來控制性能分析器是否生效,其執行效果如下所示:
add result: 2
used time: 0
mul result: 10
上述程式碼中裝飾器的呼叫等價於:
add = function_performance_statistics(True)(add(1, 1))
mul = function_performance_statistics(False)(mul(10))
寫一個日誌記錄器
# 做一個logger
def logging(filename="", level=0):
def wrapper(func):
def log(*args, **kwargs):
with open(filename, "a") as file:
line = "[LEVEL: {}] {}, {}\n".format(level, args, kwargs)
file.write(line)
file.close()
# 需要有返回值就return,否則就不用return
return func(*args, **kwargs)
return log
return wrapper
@logging(filename="query.log", level=1)
def query(msg):
print(msg, " be carried.")
return "`{}` has beed logged.".format(msg)
print(query("select * from user where userid = 2614677"))
總結
Python裝飾器的核心就是裝飾,實質就是被裝飾函式效能的增強。