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

    1、解释器入门

    写代码要遵循开放封闭原则,那么什么是开放封闭原则呢,简单的说就是:已经实现的功能代码块不允许被修改,但可以被扩展。即:

    开放:对扩展开发;封闭:已经实现的代码块

    那么问题来了如何在不更改原有代码前提下实现性能的添加,装饰器就是一个很好的用法

    例如:我需要在“登录系统前添加验证功能”,在不更改现有的代码该如何实现?

    def test(name):
        print("登录系统___%s" % name)
    
    test("张三")

    1)方法1:也许有人会想到使用闭包实现,如

    def outer(func):
        def inner(name):
            print("验证——————————")
            func(name)
        return inner
    
    
    def test(name):
        print("登录系统___%s" % name)
    
    
    test = outer(test)
    test("张三")
    
    #输出结果
    验证——————————
    登录系统___张三

    那么问题来了,这样的话在每个文件不同作用域里调用test功能之前都需要添加第12行: test = outer(test),那如果这样的需要添加位置较多的话也不现实,且比较难于查找,出现缺漏的结果也可以自行想象。这里就可以使用方法2

    2)方法2:使用装饰器

     1 def outer(func):
     2     def inner(name):
     3         print("验证——————————")
     4         func(name)
     5     return inner
     6 
     7 
     8 @outer
     9 def test(name):
    10     print("登录系统___%s" % name)
    11 
    12 
    13 test("张三")
    14 
    15 #输出结果
    16 验证——————————
    17 登录系统___张三

    这里可以看到只需要在test函数前加上 @outer  就可以实现,也可以这么理解  @outer --> test = outer(test)

    当装饰的函数有参数时装饰器内部也必须要定义形参,即 第 2 行,在第 4 行时也必须传递参数进行调用

    多个函数使用同样的验证功能时也是如此

     1 def outer(func):
     2     def inner(name):
     3         print("验证——————————")
     4         func(name)
     5     return inner
     6 
     7 
     8 @outer
     9 def test1(name):
    10     print("登录系统___%s" % name)
    11 
    12 
    13 @outer
    14 def test2(name):
    15     print("查询余额___%s" % name)
    16 
    17 
    18 test1("张三")
    19 test2("李四")
    20 
    21 #输出结果
    22 验证——————————
    23 登录系统___张三
    24 验证——————————
    25 查询余额___李四

    2、多个装饰器

     1 def outer1(func):
     2     print("_____装饰器outer1____")
     3     def inner1():
     4         print("———inner1———————")
     5         func()
     6     return inner1
     7 
     8 def outer2(func):
     9     print("_____装饰器outer2____")
    10     def inner2():
    11         print("———inner2———————")
    12         func()
    13     return inner2
    14 
    15 @outer1
    16 @outer2
    17 def test():
    18     pass
    19 
    20 test()
    21 
    22 #输出结果
    23 _____装饰器outer2____
    24 _____装饰器outer1____
    25 ———inner1———————
    26 ———inner2———————

    从结果也可以看到,当有多个装饰器时,装饰器是从内往外装饰,即:1)@outer2-->   test = outer2(test)   2) @outer1--> test = outer1(test) 

    执行到,15,16开始装饰时就会有输出输出23,24行,原因请看上边1)2),在装饰时也会执行outer2(),outer1()两个函数,所以会有输出结果

    3、装饰器带返回值

     1 def outer(func):
     2     def inner(a, b):
     3         ret = func(a, b)
     4         return ret
     5     return inner
     6 
     7 @outer
     8 def test(a, b):
     9     return a + b
    10 
    11 ret = test(5, 2)
    12 print("-----%d" % ret)
    13 
    14 #输出结果
    15 -----7

    当装饰的函数有返回值时需要将返回值返回,如第 3,4 行

    4、通用装饰器

     1 def outer(func):
     2     def inner(*args, **kwargs):
     3         ret = func(*args, **kwargs)
     4         return ret
     5     return inner
     6 
     7 @outer
     8 def test1(a):
     9     return a ** 2
    10 
    11 @outer
    12 def test2(a, b, c):
    13     return a * b * c
    14 
    15 print(test1(3))
    16 print(test2(2, 3, c=5))
    17 
    18 #输出结果
    19 9
    20 30

    当多个函数都是用同一个装饰器的时候,参数不一致的问题,就的使用通用装饰器来解决,通用即所有的函数都适用的意思。

    如上所示,test1与test2函数的参数不一致,也可以用同样的装饰器装饰,第2,3行解决

    5、带参数的装饰器

     1 def f1(flag=1):
     2     def outer(func):
     3         def inner(*args, **kwargs):
     4             if (flag == 2):
     5                 print("______%d" % flag)
     6                 ret = func(*args, **kwargs)
     7             else:
     8                 print("______%d" % flag)
     9                 ret = func(*args, **kwargs)
    10             return ret
    11         return inner
    12     return outer
    13 
    14 @f1(2)
    15 def test(a):
    16     return a ** 2
    17 
    18 print(test(3))
    19 
    20 #输出结果
    21 ______2
    22 9

    当当需要通过不同参数判断装饰器该实现的不同结果时,带参数的装饰器就出现了,如上所示,在装饰器最外层在嵌套一个函数用与接收参数,通过第 4 行判断参数选择相应的功能

    下面说说 14行  的执行流程  1)@f1(2) --> f1(2)  执行 f1函数并传值 2 ;   2)f1 函数返回 outer --->@outer;3)@outer --> test = outer(test)

    以上就是我对装饰器的一些个人理解了

  • 相关阅读:
    第十一课:Python语句讲解
    第十节课:再议数据结构与数据类型
    第九节课:这些难缠的符号
    第八节课:基本数据结构习题
    第七节课:字典
    第六节课:元组和集合
    第五节课:Python列表的应用
    Oracle问题处理
    springmvc读取服务器磁盘图片,显示于前台页面
    spring从服务器磁盘读取图片,然后显示于前端页面上
  • 原文地址:https://www.cnblogs.com/yhongji/p/9512199.html
Copyright © 2011-2022 走看看