裝飾器
最簡單來說,裝飾器的作用是使用一個函數來處理另一個函數,用來擴充被裝飾的函數的功能。比如可以在函數前或函數後輸出修飾字元串,或在web中判斷是否登入等。
首先我們要知道函數的參數可以是另一個函數:1
2
3
4
5
6
7
8
9
10
11def protest(func):
def wrap():
print('Before func')
func()
print('After func')
return wrap()
def sayhello():
print('Hello,world!')
protest(sayhello)
輸出:1
2
3Before func
Hello,world!
After func
使用@函數裝飾器化後:1
2
3
4
5
6
7
8
9
10
11
12def protest(func):
def wrap():
print('Before func')
func()
print('After func')
return wrap()
@protest
def sayhello():
print('Hello,world!')
sayhello
輸出:1
2
3Before func
Hello,world!
After func
可以認為這兩個方式其實是一樣的,都是使用一個函數作為另一個函數的參數,一個函數封裝另一個函數。
使用wraps
很多時候也會使用functools的wraps來建立裝飾器,這是為了被封裝的函數能保留原來的内置屬性。
沒用wraps的修飾器:1
2
3
4
5
6
7
8
9
10
11
12
13def protest(func):
def wraptest(*args, **kwargs):
print('Before func')
func(*args, **kwargs)
return wrap
@protest
def sayhello(word):
print(word)
if __name__ == '__main__':
sayhello('hello, boy')
print(sayhello.__name__)
輸出:1
2
3Before func
hello, boy
wraptest
使用wraps的修飾器:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#!/bin/env python
from functools import wraps
def protest(func):
@wraps(func)
def wraptest(*args, **kwargs):
print('Before func')
func(*args, **kwargs)
return wrap
@protest
def sayhello(word):
print(word)
if __name__ == '__main__':
sayhello('hello, boy')
print(sayhello.__name__)
輸出:1
2
3Before func
hello, boy
sayhello
可以看到未使用wraps的sayhello函數的__name__輸出的是封裝函數wraptest的屬性,而不是被封裝函數自身的屬性,而使用wraps的輸出的是被封裝函數自身的屬性。
裝飾器用于類
裝飾器也可以用于類中函數,但如果要讓裝飾器使用執行個體方法,需要加上self,如:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21from functools import wraps
def check_money(func):
@wraps(func)
def deal(self, *args, **kwargs):
if self.money < 1:
print('Not enough money!')
func(self, *args, **kwargs)
return deal
class Talk():
def __init__(self, money):
self.money = money
@check_money
def door(self):
return self.money
if __name__ == '__main__':
T = Talk(0)
T.door()