Python裝飾器詳解
來自專欄面向信仰1 人贊了文章
裝飾器介紹
Python裝飾器是程序開發中經常使用到的功能,熟練掌握裝飾器會讓你的編程思路更加廣闊
要理解裝飾器,首先要先理解:
1. 在 Python 中「函數是一等對象」 。即函數是一種特殊類型的變數,可以和其餘變數一樣,可以作為參數傳遞給函數,也可以作為返回值返回。Python 中的整數、字元串和字典等都是一等對象。2. 函數裝飾器在導入模塊時立即執行,而被裝飾的函數只在明確調用時運行。
裝飾器實現
裝飾器本質上是python函數,它可以使其他函數在不需要做代碼變動的情況下增加新的功能,裝飾器返回值也是一個函數對象。
以下是一個簡單的例子:
假設現在有一個函數sayHi,用來輸出一句話
def sayHi(): print(Hello, World)s = sayHis()
輸出:
Hello, World
我想希望在不修改sayHi函數的情況下在其之前再輸出一句話,這種在代碼運行期間動態增加功能的方式,稱之為「裝飾器」。
本質上,裝飾器就是一個返回函數的高階函數
我們可以這麼寫:
def sayName(func): def inner(): print("Im Yu") return func return inner()def sayHi(): print(Hello, World)s = sayName(sayHi)s()
輸出:
Im YuHello, World
但代碼美中不足的是,我們每次給sayHi增加功能都需要用到類似s = sayName(sayHi)
這句話。
簡化上邊的代碼:
def sayName(func): def inner(): print("Im Yu") return func() return inner@sayNamedef sayHi(): print(Hello, World)sayHi()
輸出:
Im YuHello, World
裝飾器原理
以上代碼中,首先,在裝飾器函數sayName中,sayName需要接受一個參數func,在其內部又定義了一個inner函數,在inner函數中增加一句輸出,並返回func對象,然後sayName函數返回內部函數inner,其實就是一個閉包函數。
接下來在sayHi上邊增加一個@sayName,其意義就是在python解釋器之行到此處時,會調用裝飾器函數(sayName),並把被裝飾得函數(sayHi)作為參數傳入。此時的sayHi已經不是未加裝飾時的函數了,而是指向sayName.inner函數地址。在接下來調用sayHi()時,其實就是調用sayName.inner。
有參函數裝飾
之前的例子是對無參函數的裝飾,如果裝飾帶參數的函數該如何處理?
def sayName(func): def inner(name): print("Im Yu") return func(name) return inner@sayNamedef sayHi(name): print(Hi, + name)sayHi(siri)
輸出:
Im YuHi,siri
兩個裝飾器裝飾函數
這裡測試兩個裝飾器裝飾一個函數的結果:
def sayName(func): print(name) def inner(): print("Im Yu") return func() return innerdef sayAge(func): print(age) def inner(): print("im 30") return func() return inner@sayName@sayAgedef sayHi(): print(Hello, World)sayHi()
輸出:
agenameIm Yuim 30Hello, World
接下來分析輸出這個結果的原因:
首先,python解釋器執行到第一個裝飾器@sayName,在接下來發現裝飾器下邊不是一個函數而是另一個裝飾器,解釋器會執行第二個的裝飾器@sayAge,然後把sayHi函數傳入裝飾器,所以首先輸出了「age」,當@sayAge裝飾完成,此時的sayHi函數地址指向了sayAge.inner的地址,解釋器會返回去執行@sayName裝飾器來裝飾新的sayHi,從而輸出了「name」,接著函數當前指向sayName.inner會先輸出「Im Yu」,在這裡返回的func()其實就是返回的sayAge.inner,所以在下面輸出im 30,最後輸出原本sayHi的「Hello, World」有參裝飾器
下邊是裝飾器帶參數:
def now(time): def sayName(func): def inner(name): print(現在是: %s % time) print("Im Yu") return func(name) return inner return sayName@now(2016/10/30)def sayHi(name): print(Hello, + name)sayHi(siri)
輸出:
現在是: 2016/10/30Im YuHello,siri
以上就是python裝飾器的相關介紹
推薦閱讀:
※函數式語言 Racket 學習記錄
※第四屆函數式編程分享會
※Rust自虐旅程(一)-- Curry and Compose
※classes
※如果讓自己只能保留一種編程語言,我選擇……