python 装饰器

Posted 七月流火

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
"""

一两个这样功能简单的还能改改,但要是许多函数,新增的功能复杂怎么办?
那我们最好使用装饰器来实现。

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

  1. 高阶函数

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

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

    输出一个函数

    我们已经定义了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!
    """
  2. 嵌套函数

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

    例:

    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()

?


以上是关于python 装饰器的主要内容,如果未能解决你的问题,请参考以下文章

[TimLinux] Python 装饰器

python装饰器

python装饰器关键代码

Python装饰器

python之装饰器

python 装饰器