python 語法之 裝飾器decorator


裝飾器 decorator

或者稱為包裝器,是對函數的一種包裝。

它能使函數的功能得到擴充,而同時不用修改函數本身的代碼。

它能夠增加函數執行前、執行后的行為,而不需對調用函數的代碼做任何改變。

 

下面用一個簡單的例子介紹裝飾器:

1 # 函數hello,輸出 hello + name 的字符串 
2 def hello(name):
3     return 'hello ' + name    

下面,我們希望在每一個調用 hello 函數的時候,將輸出的字符串用 <tag>包住

比如:hello john 變成 <tag>hello john<tag>

方法1:自定義wrapper 函數

1 def wrapper(tag, func, *arg, **kvargs):
2     tag = "<" + tag + ">"              #根據參數生成 <tag>
3     return tag + func(*arg, **kvargs) + tag  #將<tag>加在func結果的首末
4 
5 if __name__ == "__main__":
6     wrapper('p', hello, 'john')              #輸出: <p>hello john<p>   

這種方法成功修改了函數 hello 的行為,不過需要修改對 hello的調用。

每一個調用hello 的地方,都要給成調用wrapper,並修改參數列表

 

方法2:自定義decorator 函數

為了不改變對 hello的調用。我們需要得到一個新的函數對象,它修改 hello的行為,並用這個對象對 hello賦值。

從而調用 hello的時候,調用的是擴充行為后的 hello

 1 def myDecorator(func, tag)
 2     def myWrapper(*arg, **kvargs):   #重新包裝func,其參數列表與func一致
 3         sign = "<" + tag + ">"
 4         return sign + func(*arg, **kvargs) + sign
 5     return wrapper2            #調用 myDecorator 能返回一個函數對象,用於給func重新賦值
 6 
 7 hello = myDecorator(hello, "div")    #用新的函數對象修改hello
 8 
 9 if __name__ == "__main__":
10     hello("john")        #輸出 <div>hello john<div>

這樣,只要hello被myDecorator 賦值一次,以后再調用hello 時,就調用的是包裝后的函數

 

方式3:python的 decorator

python 的裝飾器所做的事與方式2類似

它通過語法糖使裝飾器看起來更清晰、簡介,而不用每次都書寫方式2中第7行代碼 hello = myDecorator(hello, "div")

 1 def setTag(tag):        #由於此裝飾器需要參數,所以要再套一層
 2     def myDecorator(func):    #裝飾器的核心,接受函數對象做參數,返回包裝后的函數對象
 3         def myWrapper(*arg, **kvargs):    #包裝的具體過程
 4             sign = "<" + tag + ">"
 5             return sign + func(*arg, **kvargs) + sign
 6         return myWrapper
 7     return myDecorator
 8 
 9 @setTag("div")    #用@標簽在定義函數時套上裝飾器
10 def hello(name):
11     return 'hello' + name    

本質上,方式2 與 方式3 完成的是同一件事,只不過方式3 比方式2 代碼更簡潔,方便。

比如,現在要給 hello 函數套上三個標簽<body><div><p>

如果用方式2

hello = myDecorator(myDecorator(myDecorator(hello, "body"),"div"),"p")

如果用方式3

@myDecorator("body")
@myDecorator("div")
@myDecorator("p")
def hello(name)
    return 'hello' + name

在多個裝飾器嵌套的情況下,python內置的decorator 結構更清晰。

 

裝飾器語法總結

完成一個裝飾器需要兩步:1.定義裝飾器函數 2.在被裝飾的函數定義之前加上 @裝飾器

下面的偽代碼展示了這個過程

 1  def myDecorator(...):    #定義裝飾器,可能帶參數
 2      def decorator(func):    #裝飾器核心,以被裝飾的函數對象為參數,返回裝飾后的函數對象
 3          def wrapper(*args, **kvargs):    #裝飾的過程,參數列表適應不同參數的函數
 4              ...    #修改函數調用前的行為
 5              func(*args, **kvargs)    #調用函數
 6              ...    #修改函數調用后的行為
 7          return wrapper
 8      return decorator
 9  
10 @myDecorator(...):    #給函數加上裝飾器
11 def myFunc(...):      #自己定義的功能函數
12     ...

 

參考:

[1] The Code Ship 中關於python裝飾器的說明:http://thecodeship.com/patterns/guide-to-python-function-decorators/

[2] python 裝飾器的主要用途與例子:https://wiki.python.org/moin/PythonDecoratorLibrary

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM