装饰器
最简单来说,装饰器的作用是使用一个函数来处理另一个函数,用来扩展被装饰的函数的功能。比如可以在函数前或函数后输出修饰字符串,或在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()