本文主要講解python中decorator的歷史,然後說明decorator在python中的實現,以幫助初識decorator的pythoner能夠靈活運用decorator。裝飾器模式來自gof的23種設計模式。
在設計模式中,裝飾器模式的意圖描述如下:
attach additional responsibilities to an object dynamically. decorators provide a flexible alternative to subclassing for extending functionality.即將附加的職責動態新增到乙個物件。在擴充套件功能時,它比子類繼承的方式要來得靈活。它是面向切面程式設計的一種手段。
提出在python中,decorator最早是在pep 318 – decorators for functions and methods被提出的。
具體實現
decorator在python中形如@decorator,如:
@log
def foo():
...
我們將通過觀察位元組碼,看一看新增decorator在位元組碼層帶來了哪些變化。
首先來看函式定義產生的位元組碼:
def foo():
pass
0 load_const 0 (", line 1>)
3 make_function 0
6 store_name 0 (foo)
foo
函式的定義對應三條位元組碼。
load_const
指令將pass
對應的**物件壓入堆疊。
make_function
將**物件彈出堆疊,建立函式,並將函式壓入堆疊。
store_name
將函式彈出棧,並將它繫結到foo
變數。
此時,foo
變數即是乙個函式。
然後我們看一下加了裝飾器的函式定義對應的位元組碼:
@log
def foo():
pass
0 load_name 0 (log) <---------- 1
3 load_const 0 (", line 1>)
6 make_function 0
9 call_function 1 < --------- 2
12 store_name 1 (foo)
給foo
函式新增乙個裝飾器時,對應的位元組碼多個兩條。上面使用1、2標出。
load_name
命令是新增命令,將log
函式(裝飾器函式)壓入堆疊。
load_const
命令將foo
下的**物件壓入棧項。
make_function
命令將**物件彈出棧,從**物件生成乙個函式,壓入堆疊。
call_function
命令是新增命令,呼叫最開始壓入堆疊的裝飾器函式,然後將函式的返回值壓入堆疊。
store_name
將棧項裝飾器函式的返回值繫結到foo
變數。
也就是說,裝飾器是乙個函式,它將被裝飾的函式作為輸入,並將輸出繫結到被裝飾的函式名上。而裝飾器的使用本質上就是乙個語法糖。
煮個粟子
知道了它的內部實現,我們就可以動手了。
例如,實現乙個列印函式耗時的裝飾器:
import time
def log(func):
start = time.time()
func(*args, **kwargs)
end = time.time()
waste_time = end - start
print 'waste time:', waste_time
@log
def hello():
print 'hello, world'
hello()
hello, world
waste time: 4.29153442383e-05
Python的前世今生
pytnon入門教程筆記 1 程式語言分為編譯和解釋兩種執行方式。編譯型語言的含義 編譯是將源 轉換成目標 的過程。執行編譯的電腦程式稱為編譯器。能夠一次性地翻譯,一旦程式被編譯,不再需要編譯程式或者源 類似英文翻譯 如 c c 對於相同源 編譯所產生的目標 執行速度更快。目標 不需要編譯器就可以執...
LinkedList前世今生
1 linkedlist元素在內部儲存的實現,節點定義即指向前一元素的指標,後一元素的指標,當前元素的值。private static class entry 2 建立乙個空鍊錶。預設有個頭指標header。private transient entryheader new entry null,n...
前世今生 STL
嘛,string就是乙個用於字串處理的標準類庫,但是需要注意的是其速度可能會比直接操縱char陣列要慢一些。reverse這個方法是我一直都想找到但是沒有找到的,在判斷回文的時候格外好用。string s abcdef string ss s ss abcdef reverse ss.begin s...