Python装饰器与推导

装饰器就是为其他函数添加功能的函数。该函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。它的概念很简单,关键在于怎么使用。下面我们一步步提出更接近装饰器的需求来进行推导

首先给出要被装饰的函数,该函数传入两个任意参数,暂停1秒,然后打印index与这两个参数。

import time
def index(x,y):
    time.sleep(1)
    print('index %s %s'%(x,y))

现在,我们要统计上述函数的运行时间,最直接的在函数中加入功能直接进行统计。

#统计上述函数运行时间。解决方案一:
import time
def index(x,y):
    start = time.time()
    time.sleep(1)
    print('index %s %s'%(x,y))
    end = time.time()
    print(end-start)

进一步提出不得修改原函数功能来进行统计。但是如果重复使用则过于冗余

#不得修改源代码的时候。解决方案二:
def index(x,y):
    time.sleep(1)
    print('index %s %s'%(x,y))
start = time.time()
index(111,222)
stop = time.time()
print(stop-start)
#没有修改被装饰对象源代码和调用方式。但若重复使用冗余

再进一步我们提出要使这个统计时间的功能可以多次调用。不过函数调用方式被修改了。参数已经写如,再调用不再传参了。如该代码下图

def wrapper():
    start = time.time()
    index(111,222)
    stop = time.time()
    print(stop-start)
#减少了冗余,但是原函数调用方式被修改了。

在这里插入图片描述
下一步我们针对调用方式进行优化。直接给函数传参数。

import time
def wrapper(a,b):
    start = time.time()
    index(a,b)
    stop = time.time()
    print(stop-start)

上述方案存在的问题是一旦index的参数修改,那么wrapper需要传的参数也需要修改。那么我们再进一步优化解决这个问题。这个其实只需要我们将参数改成可变不确定参数即可*args,**kwargs。通过这个修改我们将参数写活了。

import time
def wrapper(*args,**kwargs):
    start = time.time()
    index(*args,**kwargs)
    stop = time.time()
    print(stop-start)

上述方案似乎不错,但是存在的问题这个函数只能对index函数的运行时间进行统计。如果我们要装饰名字各不相同的函数那么就需要再进一步进行改进了。直接将函数当作参数传递就形成了我们装饰器的基本形态了。关于该装饰器的更多注释见该代码下的运行与注释截图。

def outter(func):
    def wrapper(*args,**kwargs):
        start = time.time()
        func(*args,**kwargs)
        stop = time.time()
        print(stop-start)
    return wrapper  #要在全局使用,因此需要返回wrapper

在这里插入图片描述
上述注释总结起来就是被装饰的函数与原函数是在不同内存地址的函数。
上述函数看上去已经没有什么问题,但还是存在一定的问题。即被装饰函数如果有返回值的话不能返回该函数的返回值。该函数调用我们上一段写的装饰器,运行结果截图如下在这里插入图片描述
那么针对上述问题,我们该如何解决呢?
只需要将被装饰函数赋值给一个变量,然后返回变量即可解决该问题。如此我们的装饰器已经实现了,运行效果与注释见代码下图

def outter(func):
    def wrapper(*args,**kwargs):
        start = time.time()
        res=func(*args,**kwargs)
        stop = time.time()
        print(stop-start)
        return res
    return wrapper 

在这里插入图片描述
最后我们再介绍一下装饰器最常见的引用方式。这个语法糖很简单,即在被装饰对象正上方的单独一行写@装饰器名字。演示如图,装饰器的实现与调用大功告成。
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值