python之路--装饰器

一.什么是装饰器

  首先,让我们在字面上来理解。装饰,即添加额外的修饰,在不改变函数源代码和调用方式的前提下,添加额外的功能。器,在python里面,指定的函数,例如迭代器,生成器,都是函数。装饰器,本质就是函数,功能是为其他函数添加新功能。

二.装饰器遵循的原则(开放封闭原则)

  1.不改变被修饰函数的源代码

  2.不改变被修饰函数的调用方式

三.实现装饰器的原理构成

  装饰器=高级函数+函数嵌套+闭包

四.高阶函数

  高级函数的定义:

  1.函数接受的参数是个函数名

  2.函数返回一个函数名

  3.满足以上两个函数既是高阶函数

  我们来看看用高级函数实现装饰器的效果:

#利用高阶函数无法实现
import time
def foo():     #被装饰函数
    time.sleep(0.5)
    print('来自foo')

def test(func):
    start_time=time.time()
    func()
    end_time=time.time()
    print("程序运行时间:%s"%(end_time-start_time))
  return func foo
=test(foo) foo()

  我们可以发现,虽然高级函数给被修饰函数添加了额外功能,也没修改被装饰函数的调用方式,但是会多执行一次被装饰函数,与原函数实现的功能不符。所以单独使用高级函数,是无法实现装饰器功能。

五.内嵌函数

  函数嵌套:在函数定义的内部再定义函数,称为函数嵌套。如果只是在函数中再调用其他函数,不是函数嵌套。  

def  test():
    print('这是个错误的示范')

def test1():
    test()
非函数嵌套
def test1():
    def test():
        print('这是内嵌函数')
函数嵌套

6.闭包

  闭包:在一个作用域里放入定义变量,相当于打了一个包。

def bao1(name):
    print('这是闭包一,打包变量name,bao2 ')
    def bao2():
        print('这是闭包二,打包变量bao3')
        def bao3():
            print('这是闭包三,啥都没有打包')

  闭包补充知识:解压序列。

  可以一次性将序列赋值给多个变量。例如:

l=[1,2,3,4,5,6]        #序列可以是字符串,列表,元组等。
a,b,c,d,e,f=l          #序列有多少个值,则需要对应数量的变量。
print(a,b,c,d,e,f)

  解压序列应用:获取第一个及最后一个的值

l=[1,2,3,4,5,6]
a,*_,b=l   #*代表中间全部,_为将中间全部抛弃 ,也可以定义为其他变量名
print(a,b,)
示例一
l=[1,2,3,4,5,6]
a,b,*c,d=l
print('a',a,'b',b,'c',c,'d',d)

输出结果:
a 1 b 2 c [3, 4, 5] d 6
示例二

  

七.装饰器的实现

  利用高级函数,函数嵌套,实现装饰器。我们可以实现一个基本的装饰器。

import time
def test(func):
    def wrag(*args,**kwargs):  #传递被装饰函数的参数
        start_time=time.time()
        res=func(*args,**kwargs)   #返回函数的返回值
        end_time=time.time()
        print("程序运行时间:%s"%(end_time-start_time))
        return res
    return wrag

def foo():
    time.sleep(0.5)
    print('来自foo')
    return 'haha'
foo=test(foo)   
foo()

八.语法糖:@

  语法糖:对于计算器而言,没有任何意义,但是对于人类而言,会显得语法更友好。

  在使用装饰器时,我们需要将被装饰器函数名重新定义,如果有一万个被装饰函数,就需要重复操作该步骤一万次。这明显是不合理的。于是,出现了语法糖: @来帮我进行转换。在被装饰函数定义前,加上@装饰器函数名 即可。

import time
def test(func):
    def wrag():
        start_time=time.time()
        res=func()
        end_time=time.time()
        print("程序运行时间:%s"%(end_time-start_time))
        return res
    return wrag
@test   #foo=test(foo)
def foo():
    time.sleep(0.5)
    print('来自foo')
    return 'haha'

foo()
语法糖

九.有参数装饰器

 如果我们要给装饰器函数传入参数,可以使用闭包,再给装饰器加一个参数。

import time
def test1(name):
    def test(func):
        def wrag():
            print(name)
            start_time=time.time()
            res=func()
            end_time=time.time()
            print("程序运行时间:%s"%(end_time-start_time))
            return res
        return wrag
    return test
@test1('this is test1')   #test1(name)---->test--->foo=test(foo)
def foo():
    time.sleep(0.5)
    print('来自foo')
    return 'haha'

foo()
View Code

  

十.传递函数来进行装饰

要添加的额外函数有

def before():
    print 'before'
    
def after():
    print 'after'

主体函数:

def main():
    print 'main'

装饰器:

复制代码
def filter(before_func,after_func):        #要在主体函数前 和 函数后再执行的函数名
    def outer(main_func):                   
        def wrapper():
             before_result=before_func()   #如果前函数不为None,则执行
             if(before_result!=None):
                 return before_result
             main_result=main_func()        #执行主体函数
             if(main_result!=None):
                 return main_result
             after_result=after_func()     #如果后函数不为None,则执行
             if(after_result!=None):
                 return after_result
        return wrapper
    return outer
复制代码

执行结果,打印出:

before
main
after

原文地址:https://www.cnblogs.com/white-small/p/6889855.html