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

    装饰器

    • 本质是函数
    • 功能: 装饰其他函数,即为其他函数添加附加功能
    • 装饰器需要遵循的原则: 
      • 不能修改被装饰的函数
        • 例: 现在有三个函数 , 各自有其功能. 如果需要给这三个函数都添加一个日志功能. 或这三个函数都已经在线上运行了, 现在需要再新增一些功能. 可以采取的方法:
          • 修改源代码, 每个函数都添加这些功能 (风险非常大)
      • 不能修改被装饰的函数的调用方式
      • 装饰器对被装饰的函数是完全透明的. 即装饰器完全不影响原函数.

        

     1 import time
     2 def timmer(func):   # 装饰器
     3     def warpper(*args, **kwargs):
     4         start_time = time.time()
     5         func()
     6         stop_time = time.time()
     7         print('the func run time is %s' %(stop_time-start_time))
     8     return warpper
     9 
    10 @timmer
    11 def test1():
    12     time.sleep(3)
    13     print('test1')
    14 
    15 
    16 test1()

    实现装饰器知识储备:

    • 函数即"变量"
    •  1 def bar():
       2     print('bar')
       3 
       4 
       5 def foo():
       6     print('foo')
       7     bar()
       8 
       9 
      10 foo()
      11 
      12 
      13 print("=========================")
      14 
      15 # 测试函数中引用的函数可以是定义在测试函数前面, 也可以是定义在测试函数后面的. 但一定是在调用函数语句的前面.
      16 
      17 
      18 def foo1():
      19     print('foo1')
      20     bar1()
      21 
      22 
      23 def bar1():
      24     print('bar1')
      25 
      26 
      27 foo1()
      View Code
    • 高阶函数
      • a: 把一个函数名当做实参传给另外一个函数 (在不修改被装饰函数情况下为其添加功能)
        •  1 print("=========== 返回函数内存地址 ===========")
           2 
           3 
           4 def bar():
           5     print('bar')
           6 
           7 
           8 def test1(func):
           9     print(func)
          10 
          11 
          12 test1(bar)  # 返回一段内存地址
          13 
          14 
          15 print("=========== 返回函数执行结果 ===========")
          16 
          17 
          18 # 若想返回函数的执行结果而不是函数的内存地址, 需要这样更改
          19 def bar():
          20     print('bar')
          21 
          22 
          23 def test1(func):
          24     print(func)
          25     func()
          26 
          27 
          28 test1(bar)  # 返回bar
          29 
          30 
          31 print("===========  高阶函数进阶版  ===========")
          32 
          33 
          34 import time
          35 
          36 
          37 def bar():
          38     print('bar')
          39 
          40 
          41 def test1(func):  # 实现了装饰器的功能. 运行bar()函数的同时附加了计时功能. 但是改变了函数调用方式,所以这种方法不能称为装饰器.
          42     start_time = time.time()
          43     func()  # run bar
          44     stop_time = time.time()
          45     print('the func run time is %s' % (stop_time-start_time))
          46 
          47 
          48 test1(bar)
          View Code
      • 返回值中包含函数名 (不修改函数的调用方式)
        •  1 import time
           2 
           3 
           4 def bar():
           5     time.sleep(3)
           6     print('bar')
           7 
           8 
           9 def test2(func):
          10     print(func)  # 打印函数func的内存地址
          11     return func  # 返回函数func的内存地址
          12 
          13 
          14 '''
          15 test2(bar) 和 test2(bar())的区别:
          16 test2(bar) : 
          17     把函数bar()的内存地址传给函数test2
          18 
          19 test2(bar()) : (不符合高阶函数的定义)
          20     把函数bar()的运行结果传给函数test2
          21 '''
          22 t = test2(bar)
          23 print(t)
          24 
          25 t()  # 代表运行函数bar, 等同bar()
          26 
          27 
          28 print("==========================")
          29 
          30 # 下面这种写法不会报错, 也不会陷入死循环
          31 bar = test2(bar)  # 用变量bar接收函数test2()的运行结果(实际接收到的是函数bar的内存地址. 所以变量bar后面加()就可以调用函数bar())
          32 bar()  # run bar
          View Code
    • 嵌套函数
      •  1 #  函数嵌套: 在一个函数的函数体内去声明一个新的函数.
         2 
         3 
         4 def foo():
         5     print('foo')
         6 
         7     def bar():
         8         print('bar')
         9 
        10     bar()
        11 
        12 
        13 foo()
        14 
        15 
        16 print("=========== 局部作用域和全局作用域的访问顺序 ===========")
        17 x = 0
        18 def grandpa():
        19     x = 1
        20     def dad():
        21         x=2
        22         def son():
        23             x=3
        24             print(x)
        25         son()
        26     dad()  # 如果不调用dad()函数, 相当于定义了一个变量, 却没有用这个变量.
        27 grandpa()  # 返回3
        View Code
    • 高阶函数+嵌套函数 ==>装饰器

    通用版装饰器

      1 #!/usr/bin/python
      2 # -*- coding: utf-8 -*-
      3 import time
      4 
      5 print("============== 不成功的装饰器,只有高阶函数没有嵌套 ==============")
      6 def deco(func):
      7     start_time = time.time()
      8     return func
      9     stop_time = time.time()
     10     print('the func run time is %s' % (stop_time-start_time))
     11 
     12 
     13 def test1():
     14     time.sleep(3)
     15     print('in the test1')
     16 
     17 
     18 def test2():
     19     time.sleep(3)
     20     print('in the test2')
     21 
     22 
     23 test1 = deco(test1)  # 获取函数返回值,将test1的内存地址传给变量test1.
     24 print(test1)
     25 test2 = deco(test2)
     26 print(test2)
     27 
     28 '''
     29 这样这条语句的返回值是in the test1, 装饰器没有发挥作用. 因为deco()函数中return func 后面的语句遇到return并没有执行.
     30 '''
     31 
     32 
     33 print("============  成功的装饰器, 高阶函数+嵌套函数(方法1) ============")
     34 
     35 
     36 def timer(func):
     37     def deco():  # 相当于定义了一个变量, 这个变量是个函数
     38         start_time = time.time()
     39         func()
     40         stop_time = time.time()
     41         print('the func run time is %s' % (stop_time-start_time))
     42     return deco  # 返回函数deco的内存地址
     43 
     44 
     45 def test1():
     46     time.sleep(3)
     47     print('in the test1')
     48 
     49 
     50 def test2():
     51     time.sleep(3)
     52     print('in the test2')
     53 
     54 
     55 test1 = timer(test1)  # 将函数deco的内存地址赋值给变量test1
     56 test1()  # 执行deco
     57 test2 = timer(test2)
     58 test2()
     59 
     60 
     61 print("============  成功的装饰器, 高阶函数+嵌套函数(方法2) ============")
     62 
     63 
     64 def timer(func):
     65     def deco():  # 相当于定义了一个变量, 这个变量是个函数
     66         start_time = time.time()
     67         func()
     68         stop_time = time.time()
     69         print('the func run time is %s' % (stop_time-start_time))
     70     return deco  # 返回函数deco的内存地址
     71 
     72 
     73 @timer  # 这个注释其实完成了一个动作: test1 = timer(test1)
     74 def test1():
     75     time.sleep(3)
     76     print('in the test1')
     77 
     78 
     79 @timer   # 这个注释其实完成了一个动作:test2 = timer(test2)
     80 def test2():
     81     time.sleep(3)
     82     print('in the test2')
     83 
     84 
     85 test1()  # 执行deco
     86 test2()  # 执行deco
     87 
     88 '''
     89 注: 上述方法, 若是test2(arg1)函数中有参数, 则会出错.
     90     在deco里传参(def deco(arg1))可以解决这个问题, 但是test1又会出错. 
     91 '''
     92 
     93 
     94 print("============  非固定参数装饰器, 满足有参和无参的函数 (通用装饰器) ============")
     95 def timer(func):
     96     def deco(*args, **kwargs):
     97         start_time = time.time()
     98         func(*args, **kwargs)
     99         stop_time = time.time()
    100         print('the func run time is %s' % (stop_time - start_time))
    101 
    102     return deco  # 返回函数deco的内存地址
    103 
    104 
    105 @timer  # 这个注释其实完成了一个动作: test1 = timer(test1)
    106 def test1():
    107     time.sleep(3)
    108     print('in the test1')
    109 
    110 
    111 @timer  # 这个注释其实完成了一个动作:test2 = timer(test2)
    112 def test2(arg1):
    113     time.sleep(3)
    114     print('in the test2')
    115 
    116 
    117 test1()  # 执行deco
    118 test2("abc")  # 执行deco

    完善版装饰器

    • 处理函数的返回结果
      1 #!/usr/bin/python
      2 # -*- coding: utf-8 -*-
      3 print("=========== 装饰器改变了函数的返回结果. 并没有返回函数自身的返回结果 ===========")
      4 user, pwd = 'alex','abc123'
      5 def auth(func):
      6     def wrapper(*args, **kwargs):
      7         username = input("username: ")
      8         password = input("password: ")
      9 
     10         if user == username and password == pwd:
     11             print("33[32;1mUser has passed authentication33[0m")
     12             func(*args, **kwargs)  # 执行之后有一个Func的返回值,但装饰器并没有处理这个返回值
     13         else:
     14             exit("33[32;1mInvalid username or password 33[0m")
     15     return wrapper
     16 
     17 
     18 def index():
     19     print("welcome to index page")
     20     return ("from index")
     21 @auth
     22 def home():
     23     print("welcome to home page")
     24     return("from home")
     25 @auth
     26 def bbs():
     27     print("welcome to bbs page")
     28     return("from bbs")
     29 
     30 
     31 index()
     32 home()
     33 print(home)
     34 bbs()
     35 
     36 
     37 print("=========== 完善版装饰器, 返回函数自身的返回结果(方法1)===========")
     38 user, pwd = 'alex','abc123'
     39 def auth(func):
     40     def wrapper(*args, **kwargs):
     41         username = input("username: ")
     42         password = input("password: ")
     43 
     44         if user == username and password == pwd:
     45             print("33[32;1mUser has passed authentication33[0m")
     46             return func(*args, **kwargs)
     47         else:
     48             exit("33[32;1mInvalid username or password 33[0m")
     49     return wrapper
     50 
     51 
     52 def index():
     53     print("welcome to index page")
     54     return ("from index")
     55 @auth
     56 def home():
     57     print("welcome to home page")
     58     return("from home")
     59 @auth
     60 def bbs():
     61     print("welcome to bbs page")
     62     return("from bbs")
     63 
     64 
     65 index()
     66 home()
     67 print(home)
     68 bbs()
     69 
     70 
     71 print("=========== 完善版装饰器, 返回函数自身的返回结果(方法2)===========")
     72 user, pwd = 'alex','abc123'
     73 def auth(func):
     74     def wrapper(*args, **kwargs):
     75         username = input("username: ")
     76         password = input("password: ")
     77 
     78         if user == username and password == pwd:
     79             print("33[32;1mUser has passed authentication33[0m")
     80             res = func(*args, **kwargs)
     81             print("----- after authentication -----")
     82             return res
     83         else:
     84             exit("33[32;1mInvalid username or password 33[0m")
     85     return wrapper
     86 
     87 
     88 def index():
     89     print("welcome to index page")
     90     return ("from index")
     91 @auth
     92 def home():
     93     print("welcome to home page")
     94     return("from home")
     95 @auth
     96 def bbs():
     97     print("welcome to bbs page")
     98     return("from bbs")
     99 
    100 
    101 index()
    102 home()
    103 print(home)
    104 bbs()
    View Code

    终极版装饰器

    • 提供多种认证方式 (用户名密码 /SSL /ldap )
    •  1 print("=========== 终极版装饰器, 支持多种认证方式)===========")
       2 user, pwd = 'alex','abc123'
       3 def auth(auth_type):
       4     print("auth func: ", auth_type)
       5     def outer_wrapper(func):
       6         def wrapper(*args, **kwargs):
       7             print("wrapper func args ", *args, **kwargs)
       8             if auth_type == "local":
       9                 username = input("username: ")
      10                 password = input("password: ")
      11 
      12                 if user == username and password == pwd:
      13                     print("33[32;1mUser has passed authentication33[0m")
      14                     func(*args, **kwargs)  # 执行之后有一个Func的返回值,但装饰器并没有处理这个返回值
      15                 else:
      16                     exit("33[32;1mInvalid username or password 33[0m")
      17             elif auth_type == "ldap":
      18                 print('ldap')
      19         return wrapper
      20     return outer_wrapper
      21 
      22 
      23 def index():
      24     print("welcome to index page")
      25     return ("from index")
      26 @auth(auth_type = "local")
      27 def home():
      28     print("welcome to home page")
      29     return("from home")
      30 @auth(auth_type = "ldap")
      31 def bbs():
      32     print("welcome to bbs page")
      33     return("from bbs")
      34 
      35 
      36 index()
      37 home()
      38 print(home)
      39 bbs()
      View Code

  • 相关阅读:
    九九乘法表
    计算器实现
    分装的日期类
    杨辉三角
    99乘法表
    素数
    java输出100以内质数
    跳台阶
    Counting Sheep
    课上作业
  • 原文地址:https://www.cnblogs.com/cheese320/p/8933424.html
Copyright © 2011-2022 走看看