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("

    相关推荐