淺談 Python 中的Decorator(上)
有了它,程式碼看起來更優雅
前言
之前專題寫Linebot時用Flask串接Linebot的SDK,一開始只是照個官方給的Sample Code去架設Linebot,後來深入研究Sample Code後一直不太理解裡面@
的意涵,利用空檔撰寫這篇文章,加深對Decorator的觀念。
Decorator中文翻作裝飾器,裝飾Python中的class和function,它其實是Python的一種語法糖(簡化寫法),可重複利用程式碼,將程式碼化繁為簡,以@
當做開頭。
Decorator背後牽涉到很重要的觀念 — 閉包(Closure)
閉包的部分之後在記錄成一篇筆記~本文主要初步了解Decorator的概念
實作
Smaple Code(Decorator)
來看簡單範例:
def print_my_name(name):
print("My name is %s" %(name()))@print_my_name
def my_name():
return "Tom"
# My name is Tom
執行上面的範例結果,可以發現函式看起來好像沒有東西被呼叫,卻自動被執行?
那如果改成呼叫my_name()
函式的話:
def print_my_name(name):
print("My name is %s" %(name()))@print_my_name
def my_name():
return "Tom"
my_name()
呼叫my_name()
會報TypeError: 'NoneType' object is not callable
的錯誤訊息
還原Sample Code (不加Decorator)
上述有使用@
做簡化的範例程式碼,如果還原成不加Decorator的話:
def print_my_name(name):
print("My name is %s" %(name()))
return namedef my_name():
return "Tom"name = print_my_name(my_name)
由上述例子可知:
function也可作為參數傳遞並執行。
前後比較有無Decorator的範例發現,有Decorator的程式碼省略掉name = print_my_name(my_name)
。
透過範例,可以把它簡單理解為:
對一個函式進行打包的動作,後續可重複呼叫打包過的函式。
利用function可作參數傳入的特性,將
my_name()
作為參數傳入print_my_name(name)
中(做為decorator)。
原因
name = print_my_name(my_name)
表示把my_name
這個 function傳入print_my_name
做處理,再把 print_my_name(my_name)
的回傳值assign給變數name
。
一開始的my_name
是function,但是因為重新賦值的關係,my_name()
已經不是一個function,而是與 print_my_name(my_name)
的回傳值連結在一起。
print(my_name)
# None
因為print_my_name
沒有指定回傳的值,python會預設return None
,最後執行print(my_name)
時就會得到None
的結果。
解決方法
針對剛才加入Decorator範例中,呼叫my_name()
報錯問題,只需在加上@
的函式裡面做return
,回傳由外部傳入的參數即可!
def print_my_name(name):
print("My name is %s" %(name()))
return name @print_my_name
def my_name():
return "Tom"
或是單純不想印出錯誤訊息的話可以在呼叫函式時刪除()
def print_my_name(name):
print("My name is %s" %(name()))@print_my_name
def my_name():
return "Tom"
my_name
分析函數
舉剛才未使用Decorator範例,若印出name
的話:
def print_my_name(name):
print("My name is %s" %(name()))
return namedef my_name():
return "Tom"name = print_my_name(my_name)
print(name)
回傳值會是一個function物件。
若要執行function物件的內容,需改成print_my_name(my_name)()
,因為print_my_name(my_name)
只會return function
自己,必須在後面加上()
來呼叫。
def print_my_name(name):
print("My name is %s" %(name()))
return namedef my_name():
return "Tom"name = print_my_name(my_name)()
以上是目前整理Python裝飾器(Decorator)初步的用法,其實裝飾器的寫法總共有四種,更多Python Decorator的進階用法留待下一篇。
如果觀念上有不正確或是文章內容有錯誤之處
還請看過文章的人指教!