Python 装饰器

装饰器(Decorators)是 Python 的一个重要部分。所谓的装饰器,就是修改其他函数的功能的函数,使用装饰器可以在不改变原函数的基础上扩充原函数功能。

函数也是对象

在 Python 中,函数是头等公民(First-class Citizen),其本身是一个对象,这意味着:

  • 可以把函数赋予变量;
  • 可以在函数内部定义函数(函数嵌套);
  • 函数可以作为其他函数的参数传递;
  • 函数的返回值也可以是函数对象(闭包)。

示例:函数的嵌套与闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
# outer_func是外围函数
def outer_func():
name = "I'm closure"

# inner_func是嵌套函数
def inner_func(msg):
print(f'{msg}{name}')

return inner_func


closure = outer_func() # 获得一个闭包
closure('Hello, ') # Hello, I'm closure

函数装饰器

示例一:函数装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def decorator(func):
def wrapper(*args, **kwargs):
print('wrapper of decorator')
func(*args, **kwargs)

return wrapper


@decorator # 语法糖,等同于 greet = decorator(greet)
def greet(msg):
print(f'{msg}, world')


greet('hello')
greet('goodbye')

示例二:带参数的装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def repeat(num):
def decorator(func):
def wrapper(*args, **kwargs):
for i in range(num):
print('wrapper of decorator')
func(*args, **kwargs)

return wrapper

return decorator


@repeat(3) # 等同于 greet = repeat(3)(greet)
def greet(msg):
print(msg)


greet('hello world')

示例三:装饰器的嵌套

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
"""
Python也支持多个装饰器,比如写成下面这样的形式,它的执行顺序从上到下:
@decorator1
@decorator2
@decorator3def func():
...
上面的语句等同于下面这行代码:
func = decorator1(decorator2(decorator3(func)))
"""


def decorator1(func):
def wrapper(*args, **kwargs):
print('call decorator1')
func(*args, **kwargs)

return wrapper


def decorator2(func):
def wrapper(*args, **kwargs):
print('call decorator2')
func(*args, **kwargs)

return wrapper


@decorator1
@decorator2
def greet(message):
print(message)


greet('hello world') # call decorator1、call decorator2、hello world

示例四:保留原函数的元信息

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
35
36
37
38
# 打印greet函数的元信息,发现greet函数被wrapper函数取代了
def decorator(func):
def wrapper(*args, **kwargs):
print('wrapper of decorator')
func(*args, **kwargs)

return wrapper


@decorator
def greet(msg):
print(msg)


print(greet.__name__) # wrapper
help(greet) # Help on function wrapper in module __main__: wrapper(*args, **kwargs)

---------
# 使用内置的装饰器@functools.wrap,保留原函数的元信息(也就是将原函数的元信息,拷贝到对应的装饰器函数里)。
import functools


def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('wrapper of decorator')
func(*args, **kwargs)

return wrapper


@decorator
def greet(msg):
print(msg)


print(greet.__name__) # greet
help(greet) # Help on function greet in module __main__: greet(msg)

类装饰器

除了函数可以作为装饰器,类也可以作为装饰器。类装饰器主要依赖于 __call__() 函数,每当调用一次类的实例时,__call__() 函数就会被执行一次。

示例:构建类装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Count(object):
def __init__(self, func):
self.func = func
self.num_calls = 0

def __call__(self, *args, **kwargs):
self.num_calls += 1
print(f'num of calls is: {self.num_calls}')
return self.func(*args, **kwargs)


@Count # 等同于 greet = Count(greet)
def greet():
print('hello world')


for _ in range(3):
greet()

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!