python裝飾器前世今生

2021-07-12 02:54:15 字數 2307 閱讀 9557

本文主要講解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...