zoukankan      html  css  js  c++  java
  • Python学习笔记之装饰器

    装饰器简单来说,就是现有的对象,在不修改源代码和调用方式的情况,对现有的对象添加新的功能,比如插入日志,权限校验之类的。

    为什么要用装饰器?

    1、现在有这么一个对象,我要给这个对象添加一个打印日志的功能

    1 def foo():
    2     print("I'm foo function")

    2、那么可以这样改

    1 def foo():
    2     print("I'm foo function")
    3     print("logging")

    但是如果有10个对象,是不是要在10处加上打印日志的代码?那如果是50个,100个呢?这样会有大量重复的代码出现

    3、那还可以这样改,把foo当作一个参数传给日志功能不就好了么

    1 def foo():
    2     print("I'm foo function")
    3 
    4 def logging(func):
    5     print("logging")
    6     func()
    7 
    8 logging(foo)

    这样会有一个情况就是,修改了调用方式,假如这段代码已经在生产环境中运行了,而且有很多地方都引用这段代码,不可能把所有已经引用的地方全都修改了吧

    这时候就需要用到装饰器了,不用修改原来对象的代码和调用方式,添加新的功能,还可以避免写重复的代码

    函数可以赋值给变量

    例如

    1 def foo():
    2     print("I'm foo function")
    3 
    4 f = foo
    5 f()
    6 
    7 #输出结果
    8 I'm foo function

    函数名后面有小括号和没有小括号的区别

     1 def foo():
     2     print("I'm foo function")
     3 
     4 print(foo)    #没有小括号表示函数的内存地址
     5 print('---我---是---分---割---线---')
     6 print(foo())  #有小括号表示函数的执行结果
     7 
     8 #输出结果
     9 <function foo at 0x0000026EE94C8F70>
    10 ---我---是---分---割---线---
    11 I'm foo function
    12 None

    为什么要说这个函数可以赋值和有没有小括号的问题呢,因为下面会用到这个 

    没有参数的对象进行装饰

    1、还是这个例子,为其添加日志功能

    1 def foo():
    2     print("I'm foo function")

    2、下面看一下两个例子

    (1)语法糖的写法

     1 def logging(func):  #1
     2     def deco():   #3
     3         print("logging")    #6
     4         func()   #7
     5     return deco   #4
     6 
     7 @logging  #2
     8 def foo():
     9     print("I'm foo function")   #8
    10 
    11 foo()   #5
    12 
    13 #输出结果
    14 logging
    15 I'm foo function
    (注:#1 #2 #3 ....#8 其表示的意思是在调试模式下的执行顺序)

    (2)重新赋值的写法 

     1 def logging(func):    #1
     2     def deco():   #4
     3         print("logging")  #7
     4         func()   #8
     5     return deco   #5
     6 
     7 def foo():   #2
     8     print("I'm foo function")   #9
     9 
    10 foo=logging(foo)   #3
    11 foo()   #6
    12 
    13 #输出结果
    14 logging
    15 I'm foo function
    (注:#1 #2 #3 ....#9 其表示的意思是在调试模式下的执行顺序)

    这两个例子是等价关系,语法糖@logging的写法,相当于隐式的做了foo=logging(foo)

    logging(foo)返回的是deco这个函数的内存地址,被重新赋值给了foo这个函数名,所以现在foo=deco

    当执行foo()的时候,其实就是deco()

    需要注意的是foo和foo()这两个的区别,foo是表示一个内存地址,而foo()表示的是执行结果

    有参数的对象进行装饰

     1 def logging(func):
     2     def deco(*args, **kwargs):   # *args表示可以接收任意个位置参数,**kwargs表示可以接收任意个关键字参数, 位置参数*args要放在关键字参数**kwargs的前面
     3         print("logging")
     4         func(*args, **kwargs)
     5     return deco
     6 
     7 @logging
     8 def foo():
     9     print("My name is foo function")
    10 
    11 @logging
    12 def bar(a, b):
    13     print("My name is %s %s"%(a, b))
    14 
    15 @logging
    16 def ten(x, y):
    17     print("My name is %s %s"%(x, y))
    18 
    19 
    20 foo('foo')
    21 print('---我---是---分---割---线---')
    22 bar('bar', 'function')
    23 print('---我---是---分---割---线---')
    24 ten('ten', y='function')
    25 
    26 #输出结果
    27 logging
    28 My name is foo function
    29 ---我---是---分---割---线---
    30 logging
    31 My name is bar function
    32 ---我---是---分---割---线---
    33 logging
    34 My name is ten function

    可适用于不带参数的对象、带参数的对象,以及关键字参数的对象的装饰

    当然还有一些更高级的用法,比如装饰器也带参数的

    可参考以下两个文章:

    https://www.cnblogs.com/arvin-feng/p/11108799.html

    https://www.liaoxuefeng.com/wiki/1016959663602400/1017451662295584

    若以上内容表述有误,欢迎各位大神指导一下。

  • 相关阅读:
    asp.net应用程序的生命周期和iis
    跨网页公布技术
    Java面试题:异常、静态变量
    js省市级联
    python基础之介绍
    Java学习(二)有关Tomcat的进一步理解与运用
    Java学习(一)环境的配置和软件的使用
    构造方法
    自言自语
    小小叹
  • 原文地址:https://www.cnblogs.com/rainights/p/13398247.html
Copyright © 2011-2022 走看看