装饰器

time模块

1 import time
2 time.time()#1970年到此时此刻的秒数,可以用来计算程序运行的时间
3 time.sleep(5)#表示程序执行到这里的时候停一会
4 print('ahj')

 场景:计算一个代码的执行时间:

1 import time
2 def func():
3     start=time.time()#给出程序开始运行的初始时间
4     print('老板好,领导好')
5     end=time.time()#给出程序运行结束的时间
6     print(end-start)#计算程序开始运行到结束运行的时间差
7 func()

需求:通过使用time模块确实是可以计算代码执行的时间。使用上面的代码在代码量少的地方可以很容易实现,但是如果代码量很大的话,再不断重复敲代码就不合适了。那么这个重复的功能就可以通过函数来实现,到时候在不同的代码里面加上这个函数就可以实现功能即可。

 1 import time
 2 def timer(f):#计算程序执行时间的函数
 3     start = time.time()  # 给出程序开始运行的初始时间
 4     f()#这里接收到func函数然后开始运行
 5     end = time.time()  # 给出程序运行结束的时间
 6     print(end - start)  # 计算程序开始运行到结束运行的时间差
 7 def func():
 8     time.sleep(0.1)
 9     print('老板好,领导好')
10 timer(func)#在这里将func函数传递给第3行代码
11 #注意这段代码的精妙之处:执行顺序1>7>2>9>3>4>8>9>5>6
12 
13 D:\anoconda\python.exe F:/python/python学习/人工智能/第一阶段day2/14.py
14 老板好,领导好
15 0.10072994232177734
16 
17 Process finished with exit code 0

这段代码还是优点复杂,可以再改进一下

 1 import time
 2 def func():
 3     time.sleep(0.1)
 4     print('老板好,领导好')
 5 
 6 def timer():
 7     start = time.time()  # 给出程序开始运行的初始时间
 8     func()#这里接收到func函数然后开始运行
 9     end = time.time()  # 给出程序运行结束的时间
10     print(end - start)  # 计算程序开始运行到结束运行的时间差
11 
12 timer()#在这里将func函数传递给第3行代码
13 #注意这段代码的精妙之处:执行顺序1>2>6>12>7>8>3>4>9>10

继续改进

 1 import time
 2 def func():
 3     time.sleep(0.1)
 4     print('老板好,领导好')
 5 
 6 def timer(func):
 7     start = time.time()  # 给出程序开始运行的初始时间
 8     func()#这里接收到func函数然后开始运行
 9     end = time.time()  # 给出程序运行结束的时间
10     print(end - start)  # 计算程序开始运行到结束运行的时间差
11 
12 timer(func)#在这里将直接加上func函数,这样以后遇到其他函数的时候,就能够用其他函数名直接将func替换掉即可
13 #注意这段代码的精妙之处:执行顺序1>2>6>12>7>8>3>4>9>10

但是还是不够简单:再继续修改

 1 import time
 2 def func():
 3     time.sleep(0.1)
 4     print('老板好,领导好')
 5     
 6 #够建一个闭包,定义一个装饰函数
 7 def timer(func):
 8     def inner():
 9         start = time.time()  # 给出程序开始运行的初始时间
10         func()#这里接收到func函数然后开始运行,func就是被装饰的函数
11         end = time.time()  # 给出程序运行结束的时间
12         print(end - start)  # 计算程序开始运行到结束运行的时间差
13     return inner#
14 
15 func=timer(func)
16 func()#这样处理以后只要我在实际写代码的过程中,执行func那么就能够执行timer和func都能实现执行
17 #注意这段代码的精妙之处:执行顺序1>2>7>15>8>13>15>10>9>10>3>4>11>12

装饰器的作用:不想修改函数的调用方式,但是还想再原来的函数前后添加功能。

在上面的例子中:timmer就是一个装饰器函数,只是对一个函数有些装饰作用。

上面程序的执行顺序如下

再对上面的代码进行修改提升

将计算时间的功能,单独提出来

import time

def timer(func):#定义一个装饰器函数
    def inner():
        start = time.time()
        func()#被装饰的函数
        end = time.time()
        print(end - start)
    return inner

# @timer用@加上上面闭包函数的函数名形成的这么一句话叫做语法糖,这句话的作用就是替代了# func=timer(func),这段代码,这才是实际上装饰器应该有的样子
def func():
    time.sleep(0.1)
    print('老板好,领导好')
func=timer(func)
func()

进一步修改

import time

def timer(func):#定义一个装饰器函数
    def inner():
        start = time.time()
        func()#被装饰的函数
        end = time.time()
        print(end - start)
    return inner

@timer#用@加上上面闭包函数的函数名形成的这么一句话叫做语法糖,这句话的作用就是替代了# func=timer(func),这段代码,这才是实际上装饰器应该有的样子
def func():
    time.sleep(0.1)
    print('老板好,领导好')
# func=timer(func)
func()

延申

def outer():
    def inner():
        return 'inner'
    inner()
outer()

#注意这段代码的执行顺序:1>5>5>4>3>4,因为在第五行只是执行了outer函数,inner函数的返回值没有被接收,所以结果位none

D:\anoconda\python.exe F:/python/python学习/人工智能/第一阶段day2/练习.py

Process finished with exit code 0

 1 import time
 2 
 3 def timer(func):#定义一个装饰器函数
 4     def inner():
 5         start = time.time()
 6         func()#被装饰的函数
 7         end = time.time()
 8         tmsj=end - start
 9         print('代码的运行时间是:',tmsj)#注意这里一定要加上这个逗号
10         return func()
11     return inner
12 
13 @timer
14 def func():
15     time.sleep(0.1)
16     print('老板好,领导好')
17     return '新年好'
18 
19 
20 # func=timer(func)
21 print(func())
22 # ret=func()
23 #print(ret)
24 
25 D:\anoconda\python.exe F:/python/python学习/人工智能/第一阶段day2/456.py
26 老板好,领导好
27 代码的运行时间是: 0.10079765319824219
28 老板好,领导好
29 新年好
30 
31 Process finished with exit code 0

对比代码的运行结果

 1 import time
 2 
 3 def timer(func):#定义一个装饰器函数
 4     def inner():
 5         start = time.time()
 6         ret=func()#被装饰的函数
 7         end = time.time()
 8         tmsj=end - start
 9         print('代码的运行时间是:',tmsj)#注意这里一定要加上这个逗号
10         return ret
11     return inner
12 
13 @timer
14 def func():
15     time.sleep(0.1)
16     print('老板好,领导好')
17     return '新年好'
18 
19 
20 # func=timer(func)
21 print(func())
22 # ret=func()
23 #print(ret)
24 
25 D:\anoconda\python.exe F:/python/python学习/人工智能/第一阶段day2/456.py
26 老板好,领导好
27 代码的运行时间是: 0.10103273391723633
28 新年好
29 
30 Process finished with exit code 0

装饰器带参数的装饰器

 1 import time
 2 
 3 def timer(func):#定义一个装饰器函数
 4     def inner(a):
 5         start = time.time()
 6         ret=func(a)#被装饰的函数
 7         end = time.time()
 8         tmsj=end - start
 9         print('代码的运行时间是:',tmsj)#注意这里一定要加上这个逗号
10         return ret
11     return inner
12 
13 @timer
14 def func(a):
15     time.sleep(0.1)
16     print('老板好,领导好',a)#增加了变量参数a
17     return '新年好'
18 
19 
20 # func=timer(func)
21 print(func(1))
22 # ret=func()
23 #print(ret)
24 
25 
26 D:\anoconda\python.exe F:/python/python学习/人工智能/第一阶段day2/456.py
27 老板好,领导好 1
28 代码的运行时间是: 0.10066628456115723
29 新年好
30 
31 Process finished with exit code 0

带多个参数的装饰器

 1 import time
 2 
 3 def timer(f):#定义一个装饰器函数
 4     def inner(*args,**kwargs):
 5         start = time.time()
 6         ret=f(*args,**kwargs)#被装饰的函数,注意这里的函数f和前面timmer中的参数要保持一致
 7         end = time.time()
 8         tmsj=end - start
 9         print('代码的运行时间是:',tmsj)#注意这里一定要加上这个逗号
10         return ret
11     return inner
12 
13 @timer
14 def func(a,b):
15     time.sleep(0.1)
16     print('老板好,领导好',a,b)#增加了变量a
17     return '新年好'
18 
19 @timer
20 def func2(a):#增加为两个参数
21     time.sleep(0.1)
22     print('老板好,领导好',a)#增加了变量a
23     return '新年好'
24 
25 # func=timer(func)
26 
27 print(func(1,b=2))
28 print(func2(1))
29 
30 
31 D:\anoconda\python.exe F:/python/python学习/人工智能/第一阶段day2/456.py
32 老板好,领导好 1 2
33 代码的运行时间是: 0.10066032409667969
34 新年好
35 老板好,领导好 1
36 代码的运行时间是: 0.10030198097229004
37 新年好
38 
39 Process finished with exit code 0

装饰器的通用模板

 1 #装饰器的通用模板
 2 
 3 def timer(f):#定义一个装饰器函数,f是被装饰的函数
 4     def inner(*args,**kwargs):
 5        #这里加上的是被装饰函数之前要做的事
 6         ret=f(*args,**kwargs)
 7        # 这里加上的是被装饰函数之后要做的事
 8         return ret
 9     return inner
10 
11 @timer #等价于func=timer(func)
12 def func(a,b):
13     time.sleep(0.1)
14     print('老板好,领导好',a,b)#增加了变量a
15     return '新年好'
16 
17 ret=func()#注意这里的这个func代表的是innner,实际上装饰器讲的就是一个完整的闭包

代码开放封闭原则:

开放:对扩展是开放的,对于功能的扩展是开放的。
封闭:对修改是封闭的,但是不能修改原来的代码,因为未来遇到的代码可能数量会非常大,如果自己私自修改其中的某些代码,那么就会引起很多不必要的麻烦。所以不到万不得已不能修改别人以前写的代码。修改别人的代码,在专业上叫做代码重构。

 装饰器的进阶

装饰器的复习

def wrapper(func):
    def inner(*args,**kwargs):
        print('引用前要做的事')
        ret=func(*args,**kwargs)
        print('引用后要做的事')
        return ret
    return inner

@wrapper#实际上就等价于holiday=wrapper(holiday)
def holiday(day):
    print('放假%s天'%day)
    return '很开心'

ret=holiday(3)#注意ret这里所承接的内容是第12行代码的返回值
print(ret)

 

装饰器的执行过程:装饰

上面那段代码的执行顺序

对上段代码自己的理解

 1 #先构造一个装饰器的闭包
 2 
 3 def wrapper():
 4     def inner(*args,**kwargs):
 5         print('前')
 6         # ret=func(*args,**kwargs)
 7         print('后')
 8         # return ret
 9     return inner
10 
11 wrapper()()
12 
13 D:\anoconda\python.exe F:/python/python学习/人工智能/第一阶段day2/14.py
14 前
15 后
16 
17 Process finished with exit code 0

进一步改进

 1 def wrapper(func):
 2     def inner(*args,**kwargs):
 3         print('前')
 4         ret=func(*args,**kwargs)
 5         print('后')
 6         return ret
 7     return inner
 8 
 9 @wrapper #func=wrapper(func)
10 def holiday(day):
11     print('放假%s天'%day)
12     return '很开心'
13 
14 inn=holiday(3)#注意等号右边的holiday(3)就相当于inner(3)
15 print(inn)
16 
17 
18 D:\anoconda\python.exe F:/python/python学习/人工智能/第一阶段day2/14.py
19 前
20 放假3天
21 后
22 很开心
23 
24 Process finished with exit code 0

第22行的很开心是第6行和第12行代码的综合结果,第12行返回‘很开心“,然后第6行的return再把’很开心‘这行代码返回给第14行的inn,第15行执行出结果,所以第6行和第12行代码缺一不可,否则就会报none

延申

def outer(*args):
    print(args)
    #print(*args)

outer(1,2,3,4)
outer(*[1,2,3,4])
outer(*(1,2,3,4))
#三个结果完全相同

 延申进阶

def outer(*args):
    print(args)
    print(*args)
    def inner(*args):
        print('inner:',args)
    inner(*args)

outer(1,2,3,4)

#三个结果完全相同


D:\anoconda\python.exe F:/python/python学习/人工智能/第一阶段day2/456.py
(1, 2, 3, 4)
1 2 3 4
inner: (1, 2, 3, 4)

Process finished with exit code 0

 新的知识点

def wahaha():
    '''
    一个打印哇哈哈的函数
    :return:
    '''
    print('哇哈哈')
print(wahaha.__name__)#打印出函数的字符串名称
print(wahaha.__doc__)#打印出函数的注释

同理将这个新的知识点应用到上面的代码中

 1 def wrapper(func):
 2     def inner(*args,**kwargs):
 3         print('前')
 4         ret=func(*args,**kwargs)
 5         print('后')
 6         return ret
 7     return inner
 8 
 9 @wrapper #func=wrapper(func)
10 def holiday(day):
11     print('放假%s天'%day)
12     return '很开心'
13 
14 print(holiday.__name__)
15 
16 
17 D:\anoconda\python.exe F:/python/python学习/人工智能/第一阶段day2/14.py
18 inner
19 
20 Process finished with exit code 0

由于holiday在代码中实际上指代的是inner,所以打印出来的结果就是inner

再进阶

 1 from functools import wraps
 2 def wrapper(func):
 3     @wraps(func)#加上一个内置的装饰器,但是注意这里的装饰器里面含有参数
 4     def inner(*args,**kwargs):
 5         print('前')
 6         ret=func(*args,**kwargs)
 7         print('后')
 8         return ret
 9     return inner
10 
11 @wrapper #func=wrapper(func)
12 def holiday(day):
13     '''这是一个放假的通知'''
14     print('放假%s天'%day)
15     return '很开心'
16 
17 print(holiday.__name__)#加上内置的装饰器以后,打印出来的结果就是holiday本身了
18 print(holiday.__doc__)
19 
20 inn=holiday(3)#注意等号右边的holiday(3)就相当于inner(3)
21 print(inn)
22 
23 
24 D:\anoconda\python.exe F:/python/python学习/人工智能/第一阶段day2/14.py
25 holiday
26 这是一个放假的通知
27 前
28 放假3天
29 后
30 很开心
31 
32 Process finished with exit code 0

通过调用python内置的装饰器,打印出了holiday

 

 

 

 

 

 

posted @ 2019-01-19 00:59  舒畅123  阅读(103)  评论(0编辑  收藏  举报