经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Python3 » 查看文章
Python3.5装饰器原理及应用实例详解
来源:jb51  时间:2019/4/30 12:17:07  对本文有异议

本文实例讲述了Python3.5装饰器原理及应用。分享给大家供大家参考,具体如下:

1、装饰器:

(1)本质:装饰器的本质是函数,其基本语法都是用关键字def去定义的。

(2)功能:装饰其他函数,即:为其他函数添加附加功能

(3)原则:不能修改被装饰的函数的源代码,不能修改被装饰的函数的调用方式。即:装饰器对待被修饰的函数是完全透明的。

(4)简单应用:统计函数运行时间的装饰器

  1. import time
  2. #统计函数运行时间的砖装饰器
  3. def timmer(func):
  4. def warpper(*args,**kwargs):
  5. strat_time = time.time()
  6. func()
  7. stop_time = time.time()
  8. print("the func run time is %s" %(stop_time-strat_time))
  9. return warpper
  10. @timmer
  11. def test1():
  12. time.sleep(3)
  13. print("in the test1")
  14. test1()

运行结果:

in the test1
the func run time is 3.000171661376953

(5)实现装饰器知识储备:

a、函数即“变量”

b、高阶函数

c、函数嵌套

d、高阶函数+嵌套函数==》装饰器

2、装饰器知识储备——函数即“变量”

定义一个函数,相当于把函数体赋值给这个函数名。

Python解释器如何回收变量:采用引用计数。当引用有没有了时(门牌号不存在),变量就被回收了。

函数的定义也有内存回收机制,与变量回收机制一样。匿名函数没有函数名,就会被回收。

变量的使用:先定义再调用,只要在调用之前已经存在(定义)即可;函数即“变量”,函数的使用是一样的。

函数调用顺序:其他的高级语言类似,Python 不允许在函数未声明之前,对其进行引用或者调用

下面的两段代码运行效果一样:

  1. def bar():
  2. print("in the bar")
  3. def foo():
  4. print("in the foo")
  5. bar()
  6. foo()
  7. #python为解释执行,函数foo在调用前已经声明了bar和foo,所以bar和foo无顺序之分
  8. def foo():
  9. print("in the foo")
  10. bar()
  11. def bar():
  12. print("in the bar")
  13. foo()
  14.  
  15.  

运行结果:

in the foo
in the bar
in the foo
in the bar

注意:python为解释执行,函数foo在调用前已经声明了bar和foo,所以bar和foo无顺序之分

原理图为:

3、装饰器知识储备——高阶函数

满足下列其中一种即可称之为高阶函数:

a、把一个函数名当做实参传递给另一个函数(在不修改被装饰函数的情况下为其添加附加功能)

b、返回值中包含函数名(不修改函数的调用方式)

(1)高阶函数示例:

  1. def bar():
  2. print("in the bar")
  3. def test1(func):
  4. print(func) #打印门牌号,即内存地址
  5. func()
  6. test1(bar) #门牌号func=bar

运行结果:

<function bar at 0x00BCDFA8>
in the bar

(2)高阶函数的妙处——把一个函数名当做实参传递给另一个函数(在不修改被装饰函数的情况下为其添加附加功能)

  1. import time
  2. def bar():
  3. time.sleep(3)
  4. print("in the bar")
  5. #test2在不修改被修饰函数bar的代码时添加了附加的及时功能
  6. def test2(func):
  7. start_time = time.time()
  8. func() #run bar
  9. stop_time = time.time()
  10. print("the func run time is %s " %(stop_time-start_time))
  11. #调用方式发生改变,不能像原来的方法去调用被修饰的函数(所以不能实现装饰器的功能)
  12. test2(bar)
  13. #bar()
  14.  
  15.  

运行结果:

in the bar
the func run time is 3.000171661376953

(3)高阶函数的妙处——返回值中包含函数名(不修改函数的调用方式)

  1. import time
  2. def bar():
  3. time.sleep(3)
  4. print("in the bar")
  5. def test3(func):
  6. print(func)
  7. return func
  8. bar = test3(bar)
  9. bar() #run bar
  10.  
  11.  

运行结果:

<function bar at 0x00BADFA8>
in the bar

4、装饰器知识储备——嵌套函数

  1. #函数嵌套
  2. def foo():
  3. print("in the foo")
  4. def bar(): #bar函数具有局部变量的特性,不能在外部调用,只能在内部调用
  5. print("in the bar")
  6. bar()
  7. foo()

运行结果:

in the foo
in the bar

装饰器应用——模拟网站登录页面,访问需要认证登录页面

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. # Author:ZhengzhengLiu
  4. #模拟网站,访问页面和部分需要登录的页面
  5. import timer
  6. user,passwd = "liu","liu123"
  7. def auth(func):
  8. def wrapper(*args,**kwargs):
  9. username = input("Username:").strip()
  10. password = input("Password:").strip()
  11. if username == user and password == passwd:
  12. print("\033[32;1mUser has passed authentication!\033[0m")
  13. res = func(*args,**kwargs)
  14. print("-----after authentication---")
  15. return res
  16. else:
  17. exit("\033[31;1mInvalid username or password!\033[0m")
  18. return wrapper
  19. def index():
  20. print("welcome to index page!")
  21. @auth
  22. def home():
  23. print("welcome to index home!")
  24. return "from home"
  25. @auth
  26. def bbs():
  27. print("welcome to index bbs!")
  28. #函数调用
  29. index()
  30. print(home())
  31. bbs()

运行结果:

welcome to index page!
Username:liu
Password:liu123
User has passed authentication!
welcome to home page!
-----after authentication---
from home
Username:liu
Password:liu123
User has passed authentication!
welcome to bbs page!
-----after authentication---

装饰器带参数

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. # Author:ZhengzhengLiu
  4. #模拟网站,访问页面和部分需要登录的页面,多种认证方式
  5. import timer
  6. user,passwd = "liu","liu123"
  7. def auth(auth_type):
  8. print("auth func:",auth_type)
  9. def outer_wrapper(func):
  10. def wrapper(*args, **kwargs):
  11. print("wrapper func args:",*args, **kwargs)
  12. if auth_type == "local":
  13. username = input("Username:").strip()
  14. password = input("Password:").strip()
  15. if username == user and password == passwd:
  16. print("\033[32;1mUser has passed authentication!\033[0m")
  17. #被装饰的函数中有返回值,装饰器中传入的参数函数要有返回值
  18. res = func(*args, **kwargs) #from home
  19. print("-----after authentication---")
  20. return res
  21. else:
  22. exit("\033[31;1mInvalid username or password!\033[0m")
  23. elif auth_type == "ldap":
  24. print("ldap....")
  25. return wrapper
  26. return outer_wrapper
  27. def index():
  28. print("welcome to index page!")
  29. @auth(auth_type="local") #利用本地登录 home = wrapper()
  30. def home():
  31. print("welcome to home page!")
  32. return "from home"
  33. @auth(auth_type="ldap") #利用远程的ldap登录
  34. def bbs():
  35. print("welcome to bbs page!")
  36. #函数调用
  37. index()
  38. print(home()) #wrapper()
  39. bbs()
  40.  

运行结果:

更多关于Python相关内容可查看jb51专题:《Python数据结构与算法教程》、《Python Socket编程技巧总结》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》及《Python入门与进阶经典教程

希望本文所述对大家Python程序设计有所帮助。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号