zoukankan      html  css  js  c++  java
  • 装饰器

      1 ------装饰器
      2 """首先在Python中的函数是可以看做一个特殊变量的.而装饰器是建立
      3 在闭包的前提上的.
      4 闭包就是将函数当做参数传入另一个函数,两个函数的嵌套,外部函数返回
      5 内部函数的引用
      6 .装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何
      7 代码变动的前提下增
      8 加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需
      9 求的场景,
     10 比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰
     11 器是解决这类问
     12 题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无
     13 关的雷同代码并继续
     14 重用。
     15  装饰器原则:
     16 
     17 不改变源代码      - 因为函数可能在其他地方各种调用,一改动全身
     18 
     19 -- 不改变原函数调用顺序           - 源代码有自己的逻辑处理
     20 装饰器又叫做语法糖
     21 
     22 闭包简介------------------------------
     23 如果在一个函数的内部定义了另一个函数,外部的我们叫他外函数,
     24 内部的我们叫他内函数。
     25 闭包: 
     26 在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,
     27 并且外函数的
     28 返回值是内函数的引用。这样就构成了一个闭包。
     29 """
     30  #闭包函数的实例
     31  2 # outer是外部函数 a和b都是外函数的临时变量
     32  3 def outer( a ):
     33  4     b = 10
     34  5     # inner是内函数
     35  6     def inner():
     36  7         #在内函数中 用到了外函数的临时变量
     37  8         print(a+b)
     38  9     # 外函数的返回值是内函数的引用
     39 10     return inner
     40 11 
     41 12 if __name__ == '__main__':
     42 13     # 在这里我们调用外函数传入参数5
     43 14     #此时外函数两个临时变量 a是5 b是10 ,并创建了内函数,然后把内函数的引用返回存给了demo
     44 15     # 外函数结束的时候发现内部函数将会用到自己的临时变量,这两个临时变量就不会释放,会绑定给这个内部函数
     45 16     demo = outer(5)
     46 17     # 我们调用内部函数,看一看内部函数是不是能使用外部函数的临时变量
     47 18     # demo存了外函数的返回值,也就是inner函数的引用,这里相当于执行inner函数
     48 19     demo() # 15
     49 
     50 在python3中,可以用nonlocal 关键字声明 一个变量, 表示这个变量不是局部变量空间
     51 的变量,需要向上一层变量空间找这个变量。内函数修改闭包变量的方法通过nonlocal关键字。
     52 1 #修改闭包变量的实例
     53  2 # outer是外部函数 a和b都是外函数的临时变量
     54  3 def outer( a ):
     55  4     b = 10  # a和b都是闭包变量
     56  5     c = [a] #这里对应修改闭包变量的方法2
     57  6     # inner是内函数
     58  7     def inner():
     59  8         #内函数中想修改闭包变量
     60  9         # 方法1 nonlocal关键字声明
     61 10         nonlocal  b
     62 11         b+=1
     63 12         # 方法二,把闭包变量修改成可变数据类型 比如列表
     64 13         c[0] += 1
     65 14         print(c[0])
     66 15         print(b)
     67 16     # 外函数的返回值是内函数的引用
     68 17     return inner
     69 18 
     70 19 if __name__ == '__main__':
     71 20 
     72 21     demo = outer(5)
     73 22     demo() # 6  11
     74 还有一点需要注意:使用闭包的过程中,一旦外函数被调用一次返回了内函数的引用,虽然每次调用内函数,是开启一个函数执行过后消亡,但是闭包变量实际上只有一份,每次开启内函数都在使用同一份闭包变量
     75 
     76 上代码!
     77 
     78 def outer(x):
     79     def inner(y):
     80         nonlocal x
     81         print('x', x)
     82         x+=y
     83 
     84         print('y',y)
     85         return x
     86     return inner
     87 a=outer(10)
     88 print(a(1))
     89 print(a(3))
     90 
     91 # x 10
     92 # y 1
     93 # 11
     94 # x 11
     95 # y 3
     96 # 14
     97 
     98 两次分别打印出11和14,由此可见,每次调用inner的时候,使用的闭包变量x实际上是同一个。
     99 
    100  
    101 #------------------------------------装饰器
    102 import time
    103 def test():
    104   time.sleep(2)
    105   print("test is runing")
    106 
    107 def jq(func):
    108     start=time.time()
    109     print('start',start)
    110     func()
    111     end=time.time()
    112     print('end',end)
    113     print(end-start)
    114 jq(test)
    115 
    116 # start 1552095544.027457
    117 # # test is runing
    118 # # end 1552095546.028318
    119 # # 2.0008609294891357
    120 
    121 
    122 import time
    123 def test():
    124   time.sleep(2)
    125   print("test is runing")
    126 
    127 def jq(func):
    128     start=time.time()
    129     func()
    130     end=time.time()
    131     print(end-start)
    132     return func
    133 test=jq(test)
    134 test()
    135 
    136 # test is runing
    137 # 2.0007572174072266
    138 # test is runing
    139 
    140 import time
    141 def jq(func): # 这里的参数就是test
    142     def wrapper():
    143         print(456)
    144         start=time.time()
    145         func()  #现在去执行函数test,执行完test,接着往下执行
    146         end=time.time()
    147         print(end-start)
    148         print('执行结束')
    149     return wrapper # 执行函数wrapper
    150 @jq #在执行函数test之前先执行函数jq
    151 def test():
    152   print(123)
    153   time.sleep(2)
    154   print("test is runing")
    155 test()
    156 
    157 # 456
    158 # 123
    159 # test is runing
    160 # 2.0007762908935547
    161 # 执行结束
    162 
    163 
    164 
    165 
    166 # @myzsq #添加装饰器
    167 # def test(a,b):
    168 #     print("are you ok")
    169 #     return a*b
    170 #
    171 # print(test(4,8))
    172 
    173 一、无参装饰器
    174 def myzsq(func):#func为装饰器绑定的方法
    175     def tt():
    176         print("开始")
    177         cc=func()#调用test函数
    178         print("结束")
    179     return tt    
    180 @myzsq #添加装饰器
    181 def test():
    182     print("are you ok")
    183 test()
    184 
    185 # 开始
    186 # are you ok
    187 # 结束
    188 
    189 二、带参装饰器
    190 def myzsq(func):
    191     def tt(x,y):#传入test的方法参数
    192         print("开始")
    193         cc=func(x,y)
    194         print("结束")
    195         return cc
    196     return tt
    197 @myzsq
    198 def test(a,b):
    199     print("are you ok",a,b)
    200     return a+b+1
    201 
    202 print(test(3,4))
    203 
    204 # 开始
    205 # are you ok 3 4
    206 # 结束
    207 # 8
    208 
    209 (3)装饰器即可装饰带参函数也可以装饰不带参函数
    210 
    211 def myzsq(func):
    212     def tt(*args,**kwargs):#传入test的方法参数
    213         print("开始")
    214         cc=func(*args,**kwargs)
    215         print("结束")
    216         return cc
    217     return tt
    218     
    219 @myzsq #添加装饰器
    220 def test(a):
    221     print("are you ok",a)
    222     return 33
    223 
    224 print(test(10))
    225 
    226 # 开始
    227 # are you ok 10
    228 # 结束
    229 # 33
    230 
    231 
    232 """
    233 1、如果想让装饰器不修改被装饰函数的返回值,我们需要在装饰器中接受被装饰函数的返回值
    234 并Return即可。
    235 
    236 (2) 如果希望对被装饰函数进行分类处理,我们可以在绑定装饰器时传入一个参数用于
    237 对被装饰函数进行分类,但是这样我们需要在装饰器中在套一层函数,在第一层接收装
    238 饰器传递的参数,在第二层函数中接收被装饰函数。
    239 
    240 (3) 如果希望装饰器既能装饰带参的函数也可以修饰不带参的函数,我们只需要在装饰
    241 器中接收参数时,把参数定义为非固定参数即可。
    242 
    243 """
    244 (4)装饰器的高级使用
    245 
    246 以上的装饰器已经可以满足基本需求了,但是他们第一存在一个问题,被装饰的函数的返回结果会被修改。
    247 
    248 这里我们模拟一个登陆装饰器,装饰器需要对不同的被装饰函数使用不同的登陆方法,并且是返回值不被修改。
    249 
    250 user, password = 'db', '12345' 
    251    
    252 # 当装饰器也需要参入参数时我们需要给装饰器再加一层函数,  
    253 # 此时装饰器接受到的方法需要进入第二层函数进行接受,  
    254 # 第一层需要接受装饰器自己的参数  
    255     
    256 def login(login_type):  
    257     def outer_wrapper(func):  
    258         def wrapper(*agr1, **kwargs):  
    259             usernameInput = input("UserName:").strip()  
    260             passwordInput = input("Password:").strip()  
    261             if login_type == "local":  
    262                 if user == usernameInput and password == passwordInput:  
    263                     print("login successful")  
    264                     res = func(*agr1, **kwargs)  # 接受返回结果  
    265                     return res  
    266                 else:  
    267                     print("login fail")  
    268             elif login_type == "ldap":  
    269                 print("远程登录")  
    270         return wrapper  
    271     return outer_wrapper  
    272    
    273    
    274 def index():  
    275     print("welcome to index page")  
    276   
    277   
    278 @login(login_type="local")  # 对装饰分类  
    279 def home():  
    280     print("welcome to home page")  
    281     return "from home" 
    282   
    283   
    284 @login(login_type="ldap")  # 对装饰分类  
    285 def blog():  
    286     print("welcome to blog page")  
    287    
    288    
    289 index()  
    290 print(home())  
    291 blog()
    292 
    293 
    294 test = timer(test)
    295 显然有些麻烦,Python提供了一种语法糖,即:
    296 @timer
    297 这两句是等价的,只要在函数前加上这句,就可以实现装饰作用。 
    298 
    299 #--------------例如改变装饰函数的返回结果
    300 def myzsq(func):
    301     def tt(*arg,**kwargs):#传入test的方法参数
    302         print("开始")
    303         cc=func(*arg,**kwargs)
    304         print(arg) #(4,8)
    305         print("结束")
    306         return arg[0]+arg[1] #将相乘的返回结果改为相加的返回结果
    307     return tt
    308 @myzsq #添加装饰器
    309 def test(a,b):
    310     print("are you ok")
    311     return a*b
    312 
    313 print(test(4,8))

  • 相关阅读:
    premake Ubuntu下的安装
    android设置eclipse中的自动提示功能
    SharePoint 2013的100个新功能之搜索(二)
    poj 4014 Dice 贪心
    代码手写UI,xib和StoryBoard间的博弈,以及Interface Builder的一些小技巧
    Android 英文文档下载地址
    winform网络编程之TcpClient类,TcpListener类和UdpClient类
    Spring Data MongoDB 三:基本文档查询(Query、BasicQuery)(一)
    const对象默觉得文件的局部变量
    springmvc自己定义拦截器
  • 原文地址:https://www.cnblogs.com/zpdbkshangshanluoshuo/p/10502397.html
Copyright © 2011-2022 走看看