装饰器详解
来源:互联网 发布:java银行项目经验 编辑:程序博客网 时间:2024/05/24 02:47
原文地址:http://www.cnblogs.com/Wxtrkbc/p/5486253.html
一、装饰器
装饰器可以使函数执行前和执行后分别执行其他的附加功能,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator),装饰器的功能非常强大,但是理解起来有些困难,因此我尽量用最简单的例子一步步的说明这个原理。
1、不带参数的装饰器
假设我定义了一个函数f,想要在不改变原来函数定义的情况下,在函数运行前打印出start,函数运行后打印出end,要实现这样一个功能该怎么实现?看下面如何用一个简单的装饰器来实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 使用@语法放在函数的定义上面 相当于执行 f=outer(f),此时f赋值成为了一个新的outer函数,
# 此时f函数就指向了outer函数的返回值inner,inner是一个函数名,定义在oute函数里面
# 原来的f是函数名可简单理解为一个变量,作为outer函数的参数传递进去了 此时参数func相当于f
def
outer(func):
# 定义一个outer函数作为装饰器
def
inner():
# 如果执行inner()函数的话步骤如下:
print
(
'start'
)
# 1、首先打印了字符‘start’,
r
=
func()
# 2、执行func函数,func函数相当于def f(): print('中')
print
(
'end'
)
# 3、接着函数打印‘end’
return
r
# 4、将func函数的结果返回
return
inner
@outer
def
f():
# f=outer(f)=innner
print
(
'中'
)
f()
# f()相当于inner(),执行inner函数的步骤看上面定义处的注释<br>#打印结果顺序为 start 中 end
2、包含任意参数的装饰器
在实际中,我们的装饰器可能应用到不同的函数中去,这些函数的参数都不一样,那么我们怎么实现一个对任意参数都能实现功能的装饰器?还记得我写函数那篇博客中,就写一种可以接受任意参数的函数,下面来看看如何将其应用到装饰器中去
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#其实只要将上面一种不带参数的装饰器修改一下就可以了
#修改也很简单,只需将inner和func的参数改为 (*args,**kwargs)
#其他实现的过程和上面一种一样,就不再介绍了
def
outer(func):
def
inner(
*
args,
*
*
kwargs):
print
(
'start'
)
r
=
func(
*
args,
*
*
kwargs)
# 这里func(*args,**kwargs)相当于f(a,b)
print
(
'end'
)
return
r
return
inner
@outer
def
f(a,b):
print
(a
+
b)
f(
1
,
4
)
# f(1,4)相当于inner(1,4) 这里打印的结果为 start 5 end
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
def
outer2(func2):
def
inner2(
*
args,
*
*
kwargs):
print
(
'开始'
)
r
=
func2(
*
args,
*
*
kwargs)
print
(
'结束'
)
return
r
return
inner2
def
outer1(func1):
def
inner1(
*
args,
*
*
kwargs):
print
(
'start'
)
r
=
func1(
*
args,
*
*
kwargs)
print
(
'end'
)
return
r
return
inner1
@outer2
# 这里相当于执行了 f=outer1(f) f=outer2(f),步骤如下
@outer1
#1、f=outer1(f) f被重新赋值为outer1(1)的返回值inner1,
def
f():
# 此时func1为 f():print('f 函数')
print
(
'f 函数'
)
#2、f=outer2(f) 类似f=outer2(inner1) f被重新赋值为outer2的返回值inner2
# 此时func2 为inner1函数 inner1里面func1函数为原来的 f():print('f 函数')
f()
# 相当于执行 outer2(inner1)()
>>开始
# 在outer函数里面执行,首先打印 ‘开始 ’
>>start
# 执行func2 即执行inner1函数 打印 ‘start’
>>f 函数
# 在inner1函数里面执行 func1 即f()函数,打印 ‘f 函数’
>>end
# f函数执行完,接着执行inner1函数里面的 print('end')
>>结束
# 最后执行inner2函数里面的 print('结束')
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
import
functools
def
log(k
=
''):
#这里参数定义的是一个默认参数,如果没有传入参数,默认为空,可以换成其他类型的参数
def
decorator(func):
@functools
.wraps(func)
#这一句的功能是使被装饰器装饰的函数的函数名不被改变,
def
wrapper(
*
args,
*
*
kwargs):
print
(
'start'
)
print
(
'{}:{}'
.
format
(k, func.__name__))
#这里使用了装饰器的参数k
r
=
func(
*
args,
*
*
kwargs)
print
(
'end'
)
return
r
return
wrapper
return
decorator
@log
()
# fun1=log()(fun1) 装饰器没有使用参数
def
fun1(a):
print
(a
+
10
)
fun1(
10
)
# print(fun1.__name__) # 上面装饰器如果没有@functools.wraps(func)一句的话,这里打印出的函数名为wrapper
@log
(
'excute'
)
# fun2=log('excute')(fun2) 装饰器使用给定参数
def
fun2(a):
print
(a
+
20
)
fun2(
10
)
阅读全文
0 0
- Python装饰器详解
- python装饰器详解
- Python装饰器详解
- Python 装饰器详解
- python装饰器详解
- python @装饰器 详解
- Python 装饰器详解
- python装饰器详解
- Python装饰器详解
- Python装饰器详解
- 详解Python装饰器
- python装饰器详解
- python 装饰器详解
- 装饰器详解
- 详解python装饰器
- 装饰器详解
- Pyhon装饰器详解
- decorator 装饰器模板 详解
- 电阻抗成像硬件系统中的常用概念
- 策略设计模式
- PC.CRASH.v8.0交通事故再现\
- 简单动态规划(4)——从入门到放弃
- 基于html、jsp、css制作的"慕课网"首页界面设计练习
- 装饰器详解
- 迈过三重门——详解SVM及其Python实现
- VS远程调试exe无法启动解决办法
- HLMT5中input实现多种文件上传,视频上传,图片上传,调用手机摄像头,照相机,相册功能
- 1032. 挖掘机技术哪家强(20)
- Apache Spark:三种分布式部署方式比较
- 20 个顶尖的 Python 机器学习开源项目
- shell for 循环、创建多个目录和嵌套目录
- 奇怪的问题:UTF-8中字符串空格存入 ms sql server的text字段中会显示为?