0%

使用Python裝飾器(Decorator)對函式實作

Python中的decorator是一種對python語法的轉換寫法,使用decorator可以更方便的對函式作修改,也可以提高程式的可讀性。但是decorator只是一種語法糖,使用decorator並不會對語法產生改變,只是讓程式寫法可以更加的簡潔,並且讓開發者可以更方便的使用。

下面開始來說明一下,如何使用decorator來實作在函式的修改:

假設我們寫了一個執行sql的函式:

1
2
def select_execute(sql):    
return 'execute select sql query!'

如果我們想要對這個執行sql的函式,用一個debug模式來包起來,並在debug模式印出執行的sql與執行的時間,這時可以透過closure來處理函式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def debug_query(func):    
def debug_execute(sql):
exec_msg = func(sql)
exec_time = datetime.now()
debug_msg = """
Execute: {sql}
Result: {exec_msg}
Execute Time: {exec_time}"""
return debug_msg.format(**locals())
return debug_execute

>>> sql = 'SELECT * FROM TABLE'
>>> select_execute(sql) # 不使用debug模式來執行select sql
execute select sql query!

>>> func = debug_query(select_execute) # 使用debug模式來執行select sql
>>> func(sql)
Execute: SELECT * FROM TABLE
Result: execute select sql query!
Execute Time: 2017-05-20 16:09:08.953792

從上面的範例可以看到,先將執行sql的函式傳入外部函式,並在內部函式捕捉後,加上debug要印的部份進行改寫,這樣就可以將執行sql的函式包裝成debug模式。下面是使用decorator的寫法

1
2
3
4
5
6
7
8
@debug_query
def select_execute(sql):
return 'execute select sql query!'

>>> select_execute(sql)
Execute: SELECT * FROM TABLE
Result: execute select sql query!
Execute Time: 2017-05-20 16:09:08.953792

只要透過@和改寫的函式名稱,就可以簡化函式傳遞的語法,讓程式碼可以更加簡潔並達到相同效果

decorator也可以支援帶參數,如果今天要簡單的多印出一行debug宣告,並指定是哪一種query type作說明,可以透過多加上一層outter函式來傳入參數

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def debug_describe(query_type):    
def debug_query(func):
def debug_execute(sql):
exec_msg = func(sql)
exec_time = datetime.now()
descirbe = 'It is {} debug mode'.format(query_type)
debug_msg = """
{descirbe}
Execute: {sql}
Result: {exec_msg}
Execute Time: {exec_time}"""
return debug_msg.format(**locals())
return debug_execute
return debug_query

>>> func = debug_describe('select')(select_execute) # 不使用decorator寫法
>>> func(sql)
It is select debug mode
Execute: SELECT * FROM TABLEResult: execute select sql query!
Execute Time: 2017-05-20 16:09:08.962798

@debug_describe('select')
def select_execute(sql):
return 'execute select sql query!'

>>> select_execute(sql) # 使用decorator寫法It is select debug mode
Execute: SELECT * FROM TABLE
Result: execute select sql query!
Execute Time: 2017-05-20 16:09:08.962798

參考資料:
PythonDecorators
Understanding Decorators in Python
Python Decorator 四種寫法範例 Code