四、装饰器

一、装饰器的作用

  • 在不修改原函数及其调用方式的情况下对原函数功能进行扩展;
  • 装饰器的本质就是一个闭包函数;
  • 让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象;
  • 装饰器的应用在插入日志,性能测试,事务处理,缓存等场景;

二、装饰器的形成过程

2.1:简单的装饰器

计算每个函数的执行时间的功能:

import time
def  wrapper(func):
        def inner():
              start=time.time()
              func()
              end=time.time()
              print(end-start)
        return inner

def  hahaha():
        time.sleep(1)
        print('aaaaa')
hahaha=wrapper(hahaha)
hahaha()

输出结果:
aaaaa
1.0006563663482666

2.2:装饰器---语法糖

如果有多个函数,都测试他们的执行时间,每次是不是都得func1 = timer(func1)?这样还是很麻烦,因为这些函数的函数名可能是不相同,有func1,func2,graph,等等,所以更简单的方法就是python提供得语法糖。

import time
def wrapper(func):
        def inner():
               start=time.time()
               func()
               end=time.time()
               print(end-start)
        return inner
@wrapper
def  kkk():#相当于kkk=wrapper(kkk)
    print('aaaaa')
kkk()             

2.3:原函数带一个参数的装饰器

前面的装饰器都是装饰不带参数的函数,现在要装饰一个带参数的函数怎么办呢?

def timer(func):
    def inner(a):
        start = time.time()
        func(a)
        print(time.time() - start)
    return inner

@timer
def func1(a):
    print(a)

func1(1)

2.4:原函数带多个参数的装饰器

上面的装饰器已经非常完美了,但是有我们正常情况下查看函数信息的方法在此处都会失效:

def index():
    '''这是一个主页信息'''
    print('from index')

print(index.__doc__)    #查看函数注释的方法
print(index.__name__)   #查看函数名的方法

如何解决呢?

from functools import wraps

def deco(func):
    @wraps(func) #加在最内层函数正上方
    def wrapper(*args,**kwargs):
        return func(*args,**kwargs)
    return wrapper

@deco
def index():
    '''哈哈哈哈'''
    print('from index')

print(index.__doc__)
print(index.__name__)

三,开放封闭原则

3.1对扩展是开放的

  • 为什么要对扩展开放呢?
  • 任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。

3.2对修改是封闭的

  • 为什么要对修改封闭呢?
  • 就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。
  • 装饰器完美的遵循了这个开放封闭原则。

四、装饰器的主要功能和固定结构

4.1装饰器的固定格式

def timer(func):
    def inner(*args,**kwargs):
        '''执行函数之前要做的'''
        re = func(*args,**kwargs)
        '''执行函数之后要做的'''
        return re
    return inner

4.2装饰器的固定格式--wraps版

from functools import wraps

def deco(func):
    @wraps(func) #加在最内层函数正上方
    def wrapper(*args,**kwargs):
        return func(*args,**kwargs)
    return wrapper

五,带参数的装饰器

假如你有成千上万个函数使用了一个装饰器,现在你想把这些装饰器都取消掉,你要怎么做?

一个一个的取消掉? 没日没夜忙活3天.......

过两天你领导想通了,再让你加上........

def outer(flag):
    def timer(func):
        def inner(*args,**kwargs):
            if flag:
                print('''执行函数之前要做的''')
            re = func(*args,**kwargs)
            if flag:
                print('''执行函数之后要做的''')
            return re
        return inner
    return timer

@outer(False)
def func():
    print(111)

func()

六、多个装饰器装饰一个函数

def qqqxing(fun):
    def inner(*args,**kwargs):
        print('in qqxing: before')
        ret = fun(*args,**kwargs)
        print('in qqxing: after')
        return ret
    return inner

def pipixia(fun):
    def inner(*args,**kwargs):
        print('in qqxing: before')
        ret = fun(*args,**kwargs)
        print('in qqxing: after')
        return ret
    return inner
@qqqxing
@pipixia
def dapangxie():
    print('饿了吗')
dapangxie()

#@qqqxing和@pipixia的执行顺序:先执行qqqxing里面的 print('in qqxing: before'),然后跳到了pipixia里面的
#        print('in qqxing: before')
#        ret = fun(*args,**kwargs)
#        print('in qqxing: after'),完了又回到了qqqxing里面的 print('in qqxing: after')。所以就如下面的运行结果截图一样

统计多少个函数被装饰了的小应用

统计多少个函数被我装饰了
l=[]
def wrapper(fun):
    l.append(fun)#统计当前程序中有多少个函数被装饰了
    def inner(*args,**kwargs):
        # l.append(fun)#统计本次程序执行有多少个带装饰器的函数被调用了
        ret = fun(*args,**kwargs)
        return ret
    return inner

@wrapper
def f1():
    print('in f1')

@wrapper
def f2():
    print('in f2')

@wrapper
def f3():
    print('in f3')
print(l)
posted @ 2018-05-28 12:56  HaydenGuo  阅读(227)  评论(0编辑  收藏  举报