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'所占据的内存空间(可以理解为房间和房间号的关系)

https://img.jbzj.com/file_images/article/201804/2018430124156797.png?2018330124217

而语句y=x意为将变量x对字符串的引用赋值给变量y即在内存中创建一个变量y,并使其指向变量x所指向的内存空间。

https://img.jbzj.com/file_images/article/201804/2018430124221200.png?2018330124240

b、函数在Python中的存储

1.  def test():  

2.    pass  

[说明]

Python中,函数的存储和变量相似,以上面的函数为例,Python解释其主要做两件事:

  1.在内存中开辟一个内存空间,用来存储函数代码的字符串(本例中代码只有一句:pass

  2.在内存中创建一个变量test,用来指向存储函数代码字符串的内存空间(相当于test=函数体'

https://img.jbzj.com/file_images/article/201804/2018430124244894.png?201833012435

因此说在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
----------------------
分界线-------------------
暂不支持这种登录方式!