首页 > 技术文章 > 装饰器的进阶

caoyf1992 2018-02-05 17:26 原文

一、函数的开放和封闭原则

  上一篇博客说了函数的装饰器,本章博客我们接着说函数的装饰器,但是在说装饰器之前先聊一下开放封闭原则

  对扩展是开放原则

     在函数中开放原则只对扩展是开放的,为什么这么说那,因为我们在设计任何一个程序时,不可能在设计之初就把所有的功能全部想好并且在未来也不做任何改变,所以我们必须允许代码的扩展和添加新的功能。

  对代码的修改时封闭的

     怎么说那,就是我们写好一个函数,有的时候我们写的函数会有多个人调用,如果在给别人使用的过程中对原来的代码进行了修改,很有可能会影响其他已经在使用该函数的用户。

  然而装饰器却完美的遵循了开放封闭原则,下面我们继续来说一下装饰器:

二、装饰器的主要功能和固定的基本格式

  对于装饰器我们都知道它主要的功能是:在不改变被装饰的函数及被装饰的函数的执行方式下,给函数增加额外功能的函数,但是我们在查看一个函数的注释和函数名的时候,如果这个函数带有装饰器,那么我们看到是注释信息和函数名就是装饰器里面的信息,而不是原来函数的信息,实例如下:

#!/usr/bin/python
# -*- encodeing:utf-8 -*-
def wraper(f):
    def inner(*args,**kwargs):
        ''' 执行函数前的操作'''
        ret = f(*args,**kwargs)
        '''执行函数后的操作'''
        return ret
    return inner
装饰器的固定格式
def func(*args):
    '''
    此函数计算两个数值想乘的结果
    :return: 相乘得出的结果
    '''
    return  args[0]*args[1]
print(func.__doc__) # 此处是打印上面写的注释信息
print(func.__name__) # 此处打印的是函数名
ret = func(4,5)
print(ret)
正常查看
!/usr/bin/python
# -*- encodeing:utf-8 -*-
def wraper(f):
    def inner(*args,**kwargs):
        ''' 执行函数前的操作'''
        ret = f(*args,**kwargs)
        '''执行函数后的操作'''
        return ret
    return inner
@wraper
def func(*args):
    '''
    此函数计算两个数值想乘的结果
    :return: 相乘得出的结果
    '''
    return  args[0]*args[1]
print(func.__doc__) # 此处是打印上面写的注释信息(加上装饰器之后,查看结果显示的是装饰器里面的信息)
print(func.__name__) # 此处打印的是函数名 (加上装饰器之后显示的函数名是 inner)
ret = func(4,5)
print(ret)
加上装饰器之后

  如果是我加上装饰器之后还想查看源函数的信息如何解决那,这时我们可以调用一个模块进行解决:

#!/usr/bin/python
# -*- encodeing:utf-8 -*-
from functools import wraps  #  引用functools模块
def wraper(f):
    @wraps(f) # 将wraps添加在最内层的函数上
    def inner(*args,**kwargs):
        ''' 执行函数前的操作'''
        ret = f(*args,**kwargs)
        '''执行函数后的操作'''
        return ret
    return inner
@wraper
def func(*args):
    '''
    此函数计算两个数值想乘的结果
    :return: 相乘得出的结果
    '''
    return  args[0]*args[1]
print(func.__doc__) # 此处是打印上面写的注释信息(加上装饰器之后并且引用了functools模块。这时查看结果显示的是被装饰器里面的信息)
print(func.__name__) # 此处打印的是函数名 (加上装饰器并且引用了functools模块之后显示的函数名是 func)
ret = func(4,5)
print(ret)
functools

三、带有参数的装饰器

  我们已经在上面已经用到过带有装参数的装饰器了(functools),我们下面在了解一下带有参数的装饰器都干嘛使:

    假如你们公司有300个函数使用了同一个装饰器,现在那领导让你把这些装饰器全部取消掉,你该怎么做? 

      使用最笨的办法一个一个添加?这样的话需要添加多长时间?然后几天之后领导说再把那些装饰器加上吧,你什么思想?那这个时候就可以用到带有参数的装饰器:

#!/usr/bin/python
# -*- encodeing:utf-8 -*-
import  time
flag = True  #定义一个表示位
def waper(flag):
    def timmer(f):
        def inner(*args,**kwargs):
            if flag:   #判断如果flag等于Trur则执行下面的代码
                '''执行函数之前的操作'''
                start = time.time()
                ret = f(*args,**kwargs)
                end = time.time()
                print('共计用时%s秒'%(end-start))
                '''执行函数后的操作'''
                return ret
            else:  # 判断如果flag等于False则执行下面的代码
                ret = f(*args,**kwargs)
                return ret
        return inner
    return timmer
@waper(flag)   # 先执行waper   然后返回timmer    第二,返回的timmer在于@结合就等于    f1 = timmer(f1)
def f1():
    time.sleep(0.3)
    print('python大佬你好')
f1()
带有参数的装饰器

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

  在实际生产中,有的时候可能会用到多个装饰器来装饰同一个函数,下面我们就来说一下多个装饰器在装饰同一个函数具体的过程,实例如下:

#!/usr/bin/python
# -*- encodeing:utf-8 -*-
def func1(f):# 此时的f ==a1
    def inner1():
        print('wrapper1 ,before func')
        ret = f()
        print('wrapper1 ,after func')
        return  ret
    return inner1
def func2(fu):# 此时的fu == inner1
    def inner2():   
        print('wrapper2 ,before func')
        ret = fu() 
        print('wrapper2 ,after func')
        return ret
    return inner2
@func2  #第二次执行func2  此时的func2等于 a1  = func2(inner1)  返回inner2
@func1  # 先执行func1 此时func1等于  a1 = func1(a1)返回的是 inner1
def a1():
    print('in f')
a1()  # 此时执行的a1是执行inner2
多个装饰器装饰同一个函数

 

 

推荐阅读