Python装饰器原理与用法分析(建议本文用IDE调试查看下实际运行顺序)
这篇文章主要介绍了Python装饰器原理与用法,结合实例形式分析了Python装饰器的概念、原理、使用方法及相关操作注意事项,需要的朋友可以参考下
本文实例讲述了Python装饰器原理与用法。分享给大家供大家参考,具体如下:
1、装饰器的本质是函数,主要用来装饰其他函数,也就是为其他函数添加附加功能
2、装饰器的原则:
(1) 装饰器不能修改被装饰的函数的源代码
(2) 装饰器不能修改被装饰的函数的调用方式
3、实现装饰器的知识储备
(1) Python中函数即‘变量'
a、变量在Python中的存储
1. x='Tomwenxing'
2. y=x
[说明]:
当Python解释器遇到语句x='Tomwenxing'时,它主要完成了两样工作:
1.在内存中开辟了一片空间用来存储字符串‘Tomwenxing'
2.在内存从创建了一个名为x的变量,并用它指向字符串‘Tomwenxing'所占据的内存空间(可以理解为房间和房间号的关系)
而语句y=x意为将变量x对字符串的引用赋值给变量y,即在内存中创建一个变量y,并使其指向变量x所指向的内存空间。
b、函数在Python中的存储
1. def test():
2. pass
[说明]:
在Python中,函数的存储和变量相似,以上面的函数为例,Python解释其主要做两件事:
1.在内存中开辟一个内存空间,用来存储函数代码的字符串(本例中代码只有一句:pass)
2.在内存中创建一个变量test,用来指向存储函数代码字符串的内存空间(相当于test=‘函数体')
因此说在Python中函数即变量
(2) 高阶函数(下面两个条件满足任何一个即为高阶函数)
a、把一个函数名当做实参传递给另外一个函数
[对装饰器的影响]:达到“在不修改被装饰函数源代码的情况下为其添加功能”的效果
1. import time
2. def bar():
3. time.sleep(2)
4. print('in the bar')
5. def test(func):
6. start_time=time.time()
7. func()
8. stop_time=time.time()
9. print('函数的运行时间为:',stop_time-start_time)
10. test(bar)
运行结果:
in the bar
函数的运行时间为: 2.0021145343780518
b、返回值中包含函数名
[对装饰器的影响]:达到“不改变函数的调用方式“的效果
1. import time
2. def bar():
3. time.sleep(3)
4. print('in the bar')
5. def test2(func):
6. print('新添加的功能')
7. return func
8. bar=test2(bar)
9. print('--------')
10. bar()
运行结果:
新添加的功能
--------
in the bar
(3) 嵌套函数:在一个函数体内用def去声明一个新的函数(不是调用)
1. def foo():
2. print('in the foo')
3. def bar(): #声明一个新的函数,而不是调用函数
4. print('in the bar')
5. bar()
6. foo()
运行结果:
in the foo
in the bar
4、装饰器的语法:高阶函数+嵌套函数=》装饰器 (下面的例子可以用IDE的调试器调试一下,看看代码的运行顺序
1. import time
2. def timer(func):
3. print(func.__name__) # 为了显示在@语法糖处实际执行内容
4. def deco(*args,**kwargs):#使用了不定参数
5. start_time=time.time()
6. res=func(*args,**kwargs) #运行函数
7. stop_time=time.time()
8. print('运行时间:',stop_time-start_time)
9. return res # 若无返回值,则返回None
10. return deco
11. @timer #等价于test1=timer(test1)=deco,即test1()=deco()
12. def test1():
13. time.sleep(3)
14. print('in the test1')
15. @timer #等价于test2=timer(test2)=deco,即test2(name)=deco(name)
16. def test2(name):
17. time.sleep(3)
18. print('in the test2',name)
19. test1()
20. print('-------------分界线------------------------')
21. test2('Tomwenxing')
运行结果:
test1
test2
in the test1
运行时间:3.193662166595459
-------------分界线------------------------
in the test2 Tomwenxing
运行时间: 3.984385967254639
5、带参数的装饰器
1. # -*- coding:utf-8 -*-
2. user,passwd='Tomwenxing','123'
3. #如装饰器带参数,一般是三层嵌套
4. def auth(auth_type): #第一层的参数是装饰器的参数
5. def outer_wrapper(func):#第二层的参数是装饰器要装饰的目标函数
6. def wrapper(*args,**kwargs):#第三次的参数是目标函数的参数
7. if auth_type=='local':
8. username = input('Username:').strip()
9. password = input('Password:').strip()
10. if user == username and passwd == password:
11. print('用户Tomwenxing已经成功登录!')
12. res = func(*args, **kwargs) #运行目标函数
13. return res
14. else:
15. exit('用户名或密码有错误')
16. elif auth_type=='ldap':
17. print('暂不支持这种登录方式!')
18. return wrapper
19. return outer_wrapper
20. def index():
21. print('欢迎来到index页面')
22. # @decorator(arg1,arg2,…)èfunc=decorator(arg1,arg2,…)(func)
23. @auth(auth_type='local') #home=wrapper()
24. def home(name):
25. print('%s,欢迎来到home页面' %name)
26. return 'This is home page'
27. @auth(auth_type='ldap')
28. def bbs():
29. print('欢迎来到bbs页面 ')
30. index()
31. print('----------------------分界线-------------------')
32. print('函数的返回值为:',home('wenxing'))
33. print('----------------------分界线-------------------')
34. bbs()
对于带参数的装饰器,@语法糖实际执行的是
func = decorator(arg1,arg2,…)(func)
相当于执行了两侧函数,所以最终结果是得到内层的函数wrapper,而不是外侧的out_wrapper。
运行结果:
欢迎来到index页面
----------------------分界线-------------------
Username:Tomwenxing
Password:123
用户Tomwenxing已经成功登录!
wenxing,欢迎来到home页面
函数的返回值为: This is home page
----------------------分界线-------------------
暂不支持这种登录方式!