野路子码农(5)Python中的装饰器,可能是最通俗的解说

装饰器这个名词一听就充满了高级感,而且很多情况下确实也不常用。但装饰器有装饰器的好处,至少了解这个对装逼还是颇有益处的。网上有很多关于装饰器的解说,但通常都太过“循序渐进”,有的还会讲一些“闭包”之类的概念,像我这种脑子不太好使的经常就是前读后忘……所以我想自己来写一个非常通俗易懂的解说。

个人最早真正接触装饰器是在Kaggle上看别人使用numba加速,函数前一行短短的 @jit 让你的代码快到飞起,看起来也很简洁。那究竟装饰器是什么,它又能干嘛呢?

P1 装饰器的作用

装饰器的作用是对多种函数执行一个通用操作。重点是多种和通用。举个栗子来说,我写了一个计算执行时长的装饰器,那么我可以把它安在函数A上,也可以把它安在函数B上,甚至安在任何函数上,因为装饰器执行的是一个通用操作,与我把它安在哪个函数上基本无关。注意,这里我们说“多种函数”而不是“任意函数”,因为有些装饰器有特殊用途,并不能在任意函数身上通用。

P2 装饰器的本体

我们来看一下装饰器的结构:

def 装饰器(函数模板):
    骚操作 + 函数模板 (称为wrapper)
    return wrapper

所以装饰器的本质还是一个函数,这也就是为什么我们说装饰器的作用是执行一个操作,只不过和那些普通平凡的函数都不同的是,装饰器的操作是通用的。

那么问题又来了,这个”wrapper“又是什么鬼?wrapper说白了就是一系列骚操作和函数模板的集合,装饰器函数返回的就是wrapper,也就是说它返回了函数的return和你所定义的骚操作。

至于函数模板,它不是任何一个特定的函数,它只是一个泛指。我们可以来看一下wrapper的结构,这里我写的是个最通用的函数模板(通过*args和**kwargs传递任意参数):

def wrapper(*args, **kwargs):
    前置操作
    func = function(*args, **kwargs)(即函数模板)
    后置操作
    return func

func = function(*args, **kwargs) 使我们得到了函数执行的结果,无论这个函数是什么函数,而return func将结果返回,连同前后的操作一起作为wrapper扔出去。

P3 一个例子

好了,接下来我们来写个例子,一个计算执行时长的装饰器:

import time

def simple_timeit(function):
    def wrapper(*args, **kwargs):
        start = time.time() # 记录开始时间
        func = function(*args, **kwargs)
        print("用时%.4fs"%(time.time() - start)) # 输出(结束时间-开始时间)
        return func
    return wrapper

现在我们随便写两个函数,并给它们装上装饰器:

@simple_timeit
def sleep(): # 无参数函数
    time.sleep(3)
    return "Get up!!!"
@simple_timeit
def break_str(string): # 有参数函数
    txt = [t.upper() for t in string.split(" ")]
    return txt

执行一下看看结果:

可以看到对于不同的函数类型,我们的计时器都是通用的。

总的来说,装饰器能让我们的代码变得简洁,而且能在多个函数上通用。再者由于它是在函数之上额外附加的操作,所以我们只要将装饰器那一行注释掉就能关闭附加功能,而又不影响函数本体的功能,可以说非常方便啦,所以有机会还是值得一用的~

原文地址:https://www.cnblogs.com/silence-gtx/p/11239556.html