装饰器

  1. 装饰器铺垫,装饰器的本质是闭包函数

 1 # 装饰器 在python中占有举足轻重的位置
 2 
 3 
 4 # 装饰器形成的过程
 5 # 装饰器的作用
 6 # 原则:开放封闭原则
 7     # 开放
 8         # 对扩展是开放的,新增功能是可以的
 9     # 封闭
10         # 对修改是封闭的,就是发布后版本的版本的代码,就会封版,如python 的open,版本不同不能去改。
11         # 所以不能轻易的修改已经写好的代码,如果要修改,可以使用装饰器,装饰器就是解决这个的。
12         # 如果直接改原先的函数,那叫做重构
13 # 装饰器的固定模式
14 
15 
16 import time     # 导入时间模块
17 #time.time()     # 得到当前时间戳,从1970年1月1日到现在的秒数
18 #time.sleep(5)    # 睡5秒
19 
20 
21 # 测试函数执行时间的例子,
22 # def timmer(f):
23 #     starttime = time.time()
24 #     f()
25 #     endtime = time.time()
26 #     print(endtime - starttime)
27 #
28 # def func():
29 #     #starttime = time.time()
30 #     print('老板好同事好大家好')
31 #     #endtime = time.time()
32 #     #print(endtime - starttime)
33 #
34 # timmer(func)
35 
36 # --------------------------------------#
37 def func():
38     #starttime = time.time()
39     print('老板好同事好大家好')
40     #endtime = time.time()
41     #print(endtime - starttime)
42 
43 def timmer(f):  # timmer是装饰器函数,f就是被装饰的函数
44     def inner():
45         starttime = time.time()
46         f()
47         endtime = time.time()
48         print(endtime - starttime)
49     return inner
50 
51 func = timmer(func)     # 得到inner闭包函数地址,同事timmer的形参f会始终保存func函数的地址
52 func()  # 调用了闭包函数inner
53 
54 # 上面程序的流程意思:为了测试已经写好的函数的执行时间,func()函数就是之前写好的函数,现在要测试这个func函数执行时间,但不能改动func,
55 # 所以定义了一个timmer函数,函数体中定义了一个inner闭包函数(因为使用了timmer的形参f)
56 # 函数体中调用了timmer的形参f,f()前后加上了记录开始时间与结束时间,并在后面打印
57 # 使用时,func = timer(func),timer先被调用,形参是func函数名,将闭包函数inner地址返回,赋值给了func,由于闭包的特性
58 # timmer的形参f内存值是刚才传进去的func地址,不会消失。所以在调用func时,是调用了
59 # inner闭包函数,闭包函数体重的f是func函数。
60 
61 # 装饰器的作用:不想修改函数的调用方式,但是还想再原来的函数前后添加功能
62 # timmer就是一个装饰器函数,装饰了func函数,只是对一个函数 有一些装饰的作用
View Code

   2.逐步走向完整的装饰器

# 语法糖的概念:形容一个代码被改造后,用起来很爽,很开心。
# 语法糖的例子,例如上面装饰器函数和被装饰的函数的例子,如果在被装饰的函数的上面,加一个(@装饰器函数名)的字样
# 就相当于默认使用了func = timmer(func)
@timmer     # 语法糖,有了这句话,下面的 func = timmer(func)就不调用了,默认就告诉func这个被装饰的函数使用的装饰器是timmer
def func():     # 被装饰的函数
    #starttime = time.time()
    print('老板好同事好大家好')
    #endtime = time.time()
    #print(endtime - starttime)

def timmer(f):  # timmer是装饰器函数,f就是被装饰的函数
    def inner():
        starttime = time.time()
        f()
        endtime = time.time()
        print(endtime - starttime)
    return inner

#func = timmer(func)  # 因为在被装饰的函数的上面加了(@装饰器函数名),所以这行代码可以不用,默认就具有了这行代码的效果
func()  # 调用了闭包函数inner



# -进一步:装饰器装饰函数,将被装饰的函数的返回值返回-#
def timmer2(f):  # timmer是装饰器函数,f就是被装饰的函数
    def inner():
        starttime = time.time()
        ret = f()   # 运行被装饰的函数,并接收被装饰的函数的返回值
        endtime = time.time()
        print(endtime - starttime)
        return ret  # 将被装饰的函数的返回值返回
    return inner

@timmer2
def func2():
    print('老板好同事好大家好')
    return '新年好'

#func2 = timmer2(func2)
ret = func2()  # 调用了闭包函数inner

print(ret)  # 新年好




# -再进一步:装饰带参数和带返回值的函数。装饰器装饰函数,将被装饰的函数的参数传递进去,返回值也要返回,#
def timmer3(f):  # timmer是装饰器函数,f就是被装饰的函数
    def inner(a, b):   # 加入被装饰的函数需要的参数
        starttime = time.time()
        ret = f(a, b)   # 运行被装饰的函数,传递被装饰的函数需要的参数并接收被装饰的函数的返回值
        endtime = time.time()
        print(endtime - starttime)
        return ret  # 将被装饰的函数的返回值返回
    return inner

@timmer3    # 相当于执行了func3 = timmer3(func3)
def func3(a, b):
    print('老板好同事好大家好', a, b)
    return '新年好'

#func3 = timmer3(func3)
ret = func3(1234567, 5)  # 调用了闭包函数inner

print(ret)  # 新年好



# -再进一步:装饰带参数和带返回值的函数。装饰器装饰带N个参数的函数,被装饰器的函数有的是1个参数的,有的是2个参数,参数是不知道有多少个的。这是完整的装饰器应有的东西
def timmer4(f):  # timmer是装饰器函数,f就是被装饰的函数
    def inner(*args, **kwargs):   # 加入被装饰的函数需要的参数,使用*args接收动态的位置参数,使用**kwargs接收动态的关键字参数。此种方法接收参数为万能
        starttime = time.time()
        ret = f(*args, **kwargs)   # 运行被装饰的函数,传递被装饰的函数需要的参数并接收被装饰的函数的返回值,调用函数时,传递的参数加上*表示打散后传入,打散成元组
        endtime = time.time()
        print(endtime - starttime)
        return ret  # 将被装饰的函数的返回值返回
    return inner

@timmer4    # 相当于执行了func3 = timmer3(func3)
def func4(a):
    print('老板好同事好大家好', a)
    return '新年好'

@timmer4    # 相当于执行了func3 = timmer3(func3)
def func5(a, b):
    print('老板好同事好大家好', a, b)
    return '新年好'

#func3 = timmer3(func3)
ret = func5(1234567, 5)  # 调用了闭包函数inner
ret = func4(1234567)  # 调用了闭包函数inner
print(ret)  # 新年好




# -----------------------------------

# 装饰器的定义的固定模式
def wrapper(f):  # wrapper是装饰器函数名字,f是被装饰的函数
    def inner(*args, **kwargs):   # 加入被装饰的函数需要的参数,使用*args接收动态的位置参数,使用**kwargs接收动态的关键字参数。此种方法接收参数为万能
        '''在被装饰函数的之前要做的事'''
        ret = f(*args, **kwargs)   # 运行被装饰的函数,传递被装饰的函数需要的参数并接收被装饰的函数的返回值,调用函数时,传递的参数加上*表示打散后传入,打散成元组
        '''在被装饰函数的之后要做的事'''
        return ret  # 将被装饰的函数的返回值返回
    return inner    # 返回inner()函数地址

@wrapper    # 相当于执行了func6 = wrapper(func6)  # 有了这句话,被装饰的函数实际调用的时候,调用的是装饰器中inner的闭包函数
def func6(a):
    print('老板好同事好大家好', a)
    return '新年好'
View Code

 

 

  3.装饰器的进阶

  1 # 装饰器的进阶
  2     # functools.wraps
  3     # 带参数的装饰器
  4     # 多个装饰器装饰同一个函数
  5 
  6 
  7 
  8 
  9 # 补充
 10 # def wahaha():
 11 #     '''
 12 #     一个打印娃哈哈的函数
 13 #     :return:
 14 #     '''
 15 #     print('娃哈哈')
 16 #
 17 # print(wahaha.__name__)   # __name__查看字符串格式的函数名字
 18 # print(wahaha.__doc__)   # 查看函数的注释
 19 
 20 from functools import  wraps    # wraps是一个装饰器模块
 21 
 22 def wrapper(func_arg):      # func_args == holiday
 23     @wraps(func_arg)    # 使用wraps装饰了inner函数,用这个装饰之后,出现的现象是holiday.__name__就不是inner了而是holiday
 24     def inner(*args, **kwargs):
 25         print('在被装饰函数之前做的事')
 26         ret = func_arg(*args, **kwargs)
 27         print('在被装饰函数之后做的事')
 28         return ret
 29     return inner
 30 
 31 @wrapper    # holiday = wrapper(holiday)
 32 def holiday(day_arg):
 33     print('全体放假{day}天'.format(day = day_arg))
 34     return '真的'
 35 
 36 print(holiday(5))
 37 print(holiday.__name__)     # inner  当装饰器函数中的闭包函数inner没有被wraps装饰时,这里打印的是inner的名字,当wraps装饰器装饰了装饰器中的闭包函数inner时,这里打印holiday
 38 
 39 
 40 
 41 
 42 # 如果有500个函数用了一个装饰器,现在不想用了,一一个去除太麻烦,可以使用带参数的装饰器
 43 # 带参数的装饰器,就是三层的装饰器
 44 import time
 45 
 46 FLAG = True
 47 
 48 def timmer_out(flag):
 49     def timmer(func):
 50         def inner(*args, **kwargs):
 51             if flag:
 52                 start = time.time()
 53                 ret = func(*args, **kwargs)
 54                 end = time.time()
 55                 print(end - start)
 56             else:
 57                 ret = func(*args, **kwargs)
 58             return ret
 59         return inner
 60     return timmer
 61 
 62 #timer = timer_out(FLAG)
 63 @timmer_out(FLAG)   # 因为有(),所以调用timmer_out函数,参数是FLAG,因为timer_out将参数FLAG传了进去,FLAG为True,所以FLAGH为Ture的值被保留,timmer_out函数返回了timmer的地址,所以变成了@timmer,timer = timer(wahaha)
 64 def wahaha():
 65     time.sleep(0.1)
 66     print('haha')
 67 
 68 @timmer_out(FLAG)
 69 def erguotou():
 70     time.sleep(0.1)
 71     print('erguotou')
 72 
 73 wahaha()
 74 erguotou()
 75 
 76 
 77 # 多个装饰器装饰一个函数,
 78 # 深入理解 按照程序运行过程一点一点分析理解。首先碰见了@wrapper1,需要装饰一个本装饰的函数,但是发现下面的@wrapper2不是函数,所以执行到@wrapper2,@wrapper下面有一个函数
 79 # 所以知道要装饰下面的函数f,所以@wrapper2自动变成了 f = wrapper2(f),wrapper2(f)执行完毕后,返回的是inner2,因为inner2是一个函数,所以此时@wrapper1发现下面的@wrapper2变成了一个函数inner2了,
 80 # 所以@wrapper1又装饰了inner2,此时@wrapper1自动变成了 inner2 = wrapper1(inner2),wrapper1(inner2)执行完毕后,返回的是inner1,之后用调用了f(),所以先执行了inner1函数体,打印了'wrapper1, beform func'
 81 # 之后到了func,因为inner1中的func是inner2的,所以执行了inner2函数体中的'wrapper2, beform func',之后执行到inner2中的func,因为inner2中的func是f,所以执行了f的函数体'in f',之后inner2中的func
 82 # 执行完毕,执行到了'wrapper2. after func',之后inner2的函数体执行完毕,也就代表着inner1中的func执行完毕,所以执行到了inner1中的'wrapper1. after func',之后整体执行完毕
 83 
 84 
 85 # 根据代码执行顺序也可更好理解:@wrapper2先被执行,此时f = wrapper2(f),执行结束后为 f = inner2,此时wrapper2中的func实际是f
 86 # 之后@wrapper1被执行,此时f已经等于了inner2,所以inner2 = wrapper1(inner2),执行结束后返回了inner1 所以inner2变成了 inner1,同时wrapper1中的func实际是inner2
 87 # 之后用户调用了f,所以先执行最后得到的返回值inner1的函数体,打印'wrapper1, beform func',之后运行了inner1中的func,因为inner1中的func是inner2,所以执行了inner2的函数体打印了wrapper2, beform func'
 88 # 之后执行到了inner2中的func,因为inner2中的func是f,所以执行了f的函数体打印了'in f',之后f退出,执行到了inner2中的'wrapper2. after func',之后inner返回了f的返回值
 89 # 也就是inner1中的func函数被执行完毕,接收到了inner2结束后的返回值,之后执行到了inner1中的wrapper1. after func',之后inner1返回了,并将返回值返回
 90 
 91 # 简单理解:先运行wrapper1装饰器装饰前的代码,再运行wrapper2装饰器前的代码,再运行f的代码,再顺运行wrapper2装饰后的代码,再运行wrapper1装饰后的代码
 92 def wrapper1(func):     # func -> inner2
 93     def inner1(*args, **kwargs):
 94         print('wrapper1, beform func')
 95         ret = func(*args, **kwargs)
 96         print('wrapper1. after func')
 97         return ret
 98     return inner1
 99 
100 def wrapper2(func):     # func -> f
101     def inner2(*args, **kwargs):
102         print('wrapper2, beform func')
103         ret = func(*args, **kwargs)
104         print('wrapper2. after func')
105         return ret
106     return inner2
107 
108 @wrapper1   # f = wrapper1(f)   f = inner1
109 @wrapper2   # f = wrapper2(f) 执行结束后为 f = inner2
110 def f():
111     print('in f')
112 
113 
114 f()
115 
116         # wrapper1, beform func
117         # wrapper2, beform func
118         # in f
119         # wrapper2. after func
120         # wrapper1. after func
121 
122 
123 # 多个装饰器装饰一个函数的应用,记录用户的登录情况,计算这个登录函数的执行时间,则先记录登录情况,在计算函数的执行时间
View Code

 

posted @ 2018-09-02 13:34  _小溢  阅读(164)  评论(0)    收藏  举报