Python装饰器
胖虎

python装饰器

装饰器,在不改变原函数的情况下,为其增强功能。

1. 前置知识

高阶函数

在python中函数也是被视为对象的,可以作为参数传递

示例1
1
2
3
4
5
6
7
8
9
10
11

def square(n):
return n * n

def func(a, b, fun):
res = fun(a) + fun(b)
return res

print(func(2, 3, square)) # 函数square作为函数传入到函数func中

# 结果:13
示例2
1
2
3
4
5
6
7
8
9
10
11
12

def add(a, b):
return a + b

def sub(a, b):
return a - b

funcs = [add, sub] # 函数作为列表成员方便调用
print(funcs[0](1, 2))
print(funcs[1](1, 2))

# 结果:3,-1

闭包函数

声明在一个函数种的函数被称为闭包函数,它可以访问其所在外部函数的参数和变量。

1
2
3
4
5
6
7
8
9
10
def outer():
x = 5
def inner():
print(x)
return inner

outer()

# 结果是 5 ,内部函数inner引用外部函数的变量
# inner()函数就是一个闭包

2、简单的装饰器示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

import time

def calc_spend_time(func):
'''
description:
一个监测程序运行的装饰器函数。在不改动原业务函数的情况下,增添其功能。
输入一个函数,即参数为业务函数
返回一个函数,即新建的内部闭包函数(装饰过的函数)
'''
def wrapper():
# 调用前的操作
start = time.time()
# 调用业务函数
func()
# 调用后的操作
print(f'{func} is called')
print(func.__name__ + '() start')
end = time.time()
print('用时{:.5f}秒'.format(end-start))
return wrapper #返回装饰后的闭包函数

@calc_spend_time # 语法糖,相当于hello = decorator(hello)

def hello():
print('hello world!')

if __name__ == '__main__':
hello()

# hello world!
# <function hello at 0x01F2ED18> is called
# hello() start
# 用时0.00099秒

3. 业务函数带参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

def decorator(func):
'''
description: 记录日志的装饰器函数。
'''
def wrapper(*args, **kwargs):
'''
业务函数的参数通过wrapper的函数来传递
返回值通过wrapper的返回值返回
'''
value = func(*args, **kwargs) # 记录业务函数返回值
print(f'{func} is called with arguments = {args} and kwargs = {kwargs}')
print(f'{func} return value {value}')
return value # 返回业务函数的返回值
return wrapper

@decorator # 语法糖,相当于hello = decorator(hello)

def func1(*args, **kwargs):
sum = 0
for num in args:
sum += num
print(f'args = {args}, kwargs = {kwargs}')
return sum

if __name__ == '__main__':
func1(1, 2, c=3, d=4)

# args = (1, 2), kwargs = {'c': 3, 'd': 4}
# <function func1 at 0x013DED18> is called with arguments = (1, 2) and kwargs = {'c': 3, 'd': 4}
# <function func1 at 0x013DED18> return value 3

参数*args用来发送一个非键值对的可变数量的参数列表给一个函数,可看作tuple
参数**kwargs允许你将不定长度的键值对作为参数传递给一个函数,可看作dict

4. 装饰器带参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

def outer(author): # 再套一层,传入装饰器的参数
def middle(func): # 中间层传入业务函数
def wrapper(*args, **kwargs):
value = func(*args, **kwargs) # 记录业务函数返回值
print('author: ', author,
f'\n{func} is called with arguments = {args} and kwargs = {kwargs}',
f'\nreturn value: {value}')
return value # 返回业务函数的返回值
return wrapper
return middle

# @outer('lei') # 语法糖,相当于func1 = outer('lei')(func1)
def func1(*args, **kwargs):
sum = 0
for num in args:
sum += num
return sum

if __name__ == '__main__':
func1 = outer('lei')(func1)
func1(1, 2, c=3, d=4)
# # 不用语法糖等价1:
# func1 = outer('lei')(func1)
# func1(1, 2, c=3, d=4)
# # 不用语法糖等价2:
# func1 = outer('lei')(func1)(1, 2, c=3, d=4)


# 输出结果:
# author: lei
# <function func1 at 0x0192EE38> is called with arguments = (1, 2) and kwargs = {'c': 3, 'd': 4}
# return value: 3

  • Post title:Python装饰器
  • Post author:胖虎
  • Create time:2021-03-16 00:00:00
  • Post link:https://leiwei.space/2021/03/16/2021-03-14-Python装饰器/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.
 Comments