python 装饰器

装饰器是可调用的对象,其参数是另一个函数(被装饰的函数)。 装饰器可能会处理被装饰的函数,然后把它返回,或者将其替换成另一个函数或可调用对象。

装饰器特性

装饰器的一个关键特性是,它们在被装饰的函数定义之后立即运行。这通常是在导入时(即 Python 加载模块时),如下代码:

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
registry = []
def register(func):
print('running register(%s)' % func)
registry.append(func)
return func
@register
def f1():
print('running f1()')
@register
def f2():
print('running f2()')
def f3():
print('running f3()')
def main():
print('running main()')
print('registry ->', registry)
f1()
f2()
f3()
if __name__=='__main__':
main()

运行效果:
running register()
running register()
running main()
(‘registry ->’, [, ])
running f1()
running f2()
running f3()

这里主要想强调,函数装饰器在导入模块时立即执行,而被装饰的函数只在明确调用时运行。这突出了 Python 程序员所说的导入时和运行时之间的区别。

装饰器案例

1
2
3
4
5
6
7
8
9
10
def wrap(func):
def inner():
print func.__name__
return inner
@wrap
def test():
print 456
test() # 输出 test
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def document_it(func):
def new_function(*args, **kwargs):
print "running function :", func.__name__
print "Positional arguments :", args
print "keyword arguments :", kwargs
result = func(*args, **kwargs)
print "Result :", result
return result
return new_function
无论传入 document_ it() 的函数 func 是什么, 装饰器都会返回一个新的函数,其中包含函数 document_ it()
增加的额外语句。实际上,装饰器并不需要执行函数 func 中的代码,只是在结束前函数 document_it()
调用函数 func 以便得到 func 的返回结果和附加代码的结果。
@document_it
def add_ints(a, b):
return a + b
add_ints(5, 6)
输出:
running function : add_ints
Positional arguments : (5, 6)
keyword arguments : {}
Result : 11
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# -*- coding: utf-8 -*-
from functools import wraps
def wrapper(f):
@wraps(f)
def wrapper_function(*args, **kwargs):
"""这个是修饰函数"""
return f(*args, **kwargs)
return wrapper_function
@wrapper
def wrapped():
"""这个是被修饰的函数"""
print('wrapped')
print(wrapped.__doc__) # 输出`这个是被修饰的函数` ,如果不在装饰器不使用@wraps(f),则会输出 `这个是修饰函数`
print(wrapped.__name__) # 输出`wrapped`
wraps修饰器的作用就是将 被修饰的函数(wrapped) 的一些属性值(如__doc__、__module__、__name__)赋值给 修饰器函数(wrapper) ,最终让属性的显示更符合我们的直觉