python 装饰器

装饰器的实质就是一个函数,可以对其他函数进行装饰,在不改变原函数代码的基础上增加新的功能,调用方式也不改变。

比如我们有两个函数sout1,sout2

import time

def sout1():
    time.sleep(1)
	print("this is sout1")
	
	
def sout2():
    time.sleep(2)
	print("this is sout2")
    
sout1()
sout2()

# 输出
# this is sout1
# this is sout2

现在我想让每个方法执行完时输出运行需要的时间

我们可以修改代码实现

import time

def sout1():
    start = time.time()
    time.sleep(1)
	print("this is sout1")
    end = time.time()
    print("running time is",end-start)
	
	
def sout2():
     start = time.time()
     time.sleep(2)
	 print("this is sout2")
     end = time.time()
     print("running time is",end-start)

 """
输出
this is sout1
running time is 1.0009281635284424
this is sout2
running time is 2.0002005100250244
"""

一两个这样功能简单的还能改改,但要是许多函数,新增的功能复杂怎么办?

最好使用装饰器来实现。

在使用装饰前我们要先了解两个概念 高阶函数、嵌套函数

高阶函数

在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数:

接受一个或多个函数作为输入

输出一个函数

我们已经定义了sout1这个函数

sout1() // 会调用函数
"""
输出
this is sout1
running time is 1.0009281635284424
"""
print (sout)
<function sout1 at 0x02CEB780>

万物皆对象嘛

所以函数也是对象

sout1存的是地址 是对象的引用

我们新增一个引用

hello = sout1
hello()

"""
输出
this is sout1
running time is 1.0009281635284424
"""

既然是对象 当然也能作为函数的参数和返回值

例:

def test(func):
    return func

def sout():
    print("hello world!")
    
a = test(sout)
a()

"""
输出
hello world!
"""

嵌套函数

就是函数里面又定义一个函数

例:

def outer():
    print("hello")
    def inner():
        print("world!")
    inner()

outer()

"""
输出
hello
world!
"""

实现

新增功能(修改调用方式)

既然可以把函数当作参数传入,那..

我们不就可以把原有函数当作参数传进一个新的函数中,新增点功能在返回出来?

import time
   
def sout1():
    time.sleep(1)
    print("this is sout1")
   
   
def decorate(func):
    start = time.time()
    func()
    end = time.time()
    print("running time is",end-start)
   
   
   decorate(sout1)
   
   """
   输出
   this is sout1
   running time is 1.0004260540008545
   """
           

现在已经实现了不修改原有代码添加新功能了,但是调用方式和以前不一样了。

新增功能(不修改调用方式)

那怎么实现不修改原来的调用方式?还是sout1()进行调用?

我们已经知道函数也可以和变量一样,给它一个新的引用,进行调用

如:

x = 1
y = x
print(y)
"""
输出
1
"""

def sout1():
    time.sleep(1)
    print("this is sout1")
    
hello = sout1
hello()
"""
输出
this is sout1
"""

那我们想办法让进行装饰的函数 **decorate() **也返回一个函数

然后 sout1 = decorate(sout1)

不就实现了sout1()

新增功能而不修改原代码,原调用方式?

所以我们可以把decorate()中的代码再封装一下

def sout1():
    time.sleep(1)
    print("this is sout1")

# 原decorate()
# def decorate(func):
#     start = time.time()
#     func()
#     end = time.time()
#     print("running time is",end-start)

#改为:
def decorate(func):
    def inner():
        start = time.time()
        func()
        end = time.time()
        print("running time is",end-start)
    return inner


sout1 = decorate(sout1)
sout1()
"""
输出
this is sout1
running time is 1.0003764629364014
"""

成功!

然而我们还是要在 原来的函数调用前

添加类似语句 sout1 = decorate(sout1)

这个事情python可以通过语法糖@来帮我们完成

def decorate(func):
    def inner():
        start = time.time()
        func()
        end = time.time()
        print("running time is", end - start)

    return inner


@decorate  # 等同于 sout1 = decorate(sout1)
def sout1():
    time.sleep(1)
    print("this is sout1")


sout1()

posted @ 2018-07-04 14:49  七月吃瓜  阅读(150)  评论(0编辑  收藏  举报