菠菜网

济南房地产网:五分钟学会Python装饰器,看完面试不再慌

时间:6个月前   阅读:71   评论:1

本文始发于小我私家民众号:TechFlow,原创不易,求个关注


今天是Python专题的第12篇文章,我们来看看Python装饰器。

一段囧事

差不多五年前面试的时刻,我就领教过它的主要性。那时刻我Python刚刚初学乍练,看完了廖雪峰大神的博客,就去面试了。我应聘的并不是一个Python的开发岗位,然则JD当中写到了需要熟悉Python。我看网上的面经说到Python经常会问装饰器,我那时想的是装饰器我已经看过了,应该问题不大……

没想到面试的时刻还真的问到了,面试官问我Python当中的装饰器是什么。由于主要和遗忘,我支支吾吾了半天也没答上来。我隐约听到了电话那头的一声叹息……

时隔多年,我已经不记得那是一家什么公司了(估量规模也不大),但装饰器很主要这个事情给我深深打下了烙印。

装饰器本质

现在若是再有面试官问我Python中的装饰器是什么,我一句话就能给回覆了,倒不是我装逼,实际上也简直只需要一句话。Python中的装饰器,本质上就是一个高阶函数

你可能不太清晰高阶函数的界说,没关系,我们可以类比一下。在数学当中高阶导数,好比二次导数,示意导数的导数。那么这里高阶函数自然就是函数的函数,连系我们之前先容过的函数式编程,也就是说是一个返回值是函数的函数。然则这个界说是充实不必要的,也就是说装饰器是高阶函数,然则高阶函数并不都是装饰器。装饰器是高阶函数一种特殊的用法。

随便参数

在先容装饰器的详细使用之前,我们先来领会和熟悉一下Python当中的随便参数。

Python当中支持随便参数,它写成*args, **kw。示意的寄义是接受任何形式的参数

举个例子,好比我们界说一个函数:

def exp(a, b, c='3', d='f'):
    print(a, b, c, d)

我们可以这样挪用:

args = [13]
dt = {'c'4'd'5}

exp(*args, **dt)

最后输出的效果是1, 3, 4, 5。也就是说我们用一个list和dict可以示意任何参数。由于Python当中划定必选参数一定写在可选参数的前面,而必选参数是可以不用加上名称标识的,也就是可以不用写a=1,直接传入1即可。那么这些没有名称标识的必选参数就可以用一个list来示意,而可选参数是必须要加上名称标识的,这些参数可以用dict来示意,这两者相加可以示意任何形式的参数。

注重我们传入list和dict的时刻前面加上了*和**,它示意将list和dict当中的所有值睁开。若是不加的话,list和dict会被当成是整体传入。

以是若是一个函数写成这样,它示意可以接受任何形式的参数。

def exp(*args, **kw):
    pass

界说装饰器

明了了随便参数的写法之后,装饰器就不难了。

既然我们可以用*args, **kw接受任何参数。而且Python当中支持一个函数作为参数传入另外一个函数,若是我们把函数和这个函数的所有参数所有传入另外一个函数,那么不就可以实现署理了吗?

照样适才的例子,我们分外增添一个函数:


def exp(a, b, c='3', d='f'):
    print(a, b, c, d)

def agent(func, *args, **kwargs):
    func(*args, **kwargs)

args = [1]
dt = {'b'1'c'4'd'5}

agent(exp, *args, **dt)

装饰器的本质实在就是这样一个agent函数,然则若是使用的时刻需要手动传入会异常贫苦,使用起来不太利便。以是Python当中提供了特定的库,我们可以让装饰器以注解的方式使用,大大简化操作:

from functools import wraps

def wrapexp(func):
    def wrapper(*args, **kwargs):
        print('this is a wrapper')
        func(*args, **kwargs)
    return wrapper


@wrapexp
def exp(a, b, c='3', d='f'):
    print(a, b, c, d)


args = [13]
dt = {'c'4'd'5}

exp(*args, **dt)

在这个例子当中,我们界说了一个wrapexp的装饰器。我们在其中的wrapper方式当中实现了装饰器的逻辑,wrapexp当中传入的参数func是一个函数,wrapper当中的参数则是func的参数。以是我们在wrapper当中挪用func(*args, **kw),就是挪用打上了这个注解的函数自己。好比在这个例子当中,我们没有做任何事情,只是在原样挪用之前多输出了一行’this is a wrapper',示意我们的装饰器挪用乐成了。

装饰器用途

我们理解了装饰器的基本使用方式之后,自然而然地会问一个自然的问题,学会了它事实有什么用呢?

若是你从上面的例子当中没有领会到装饰器的壮大,不如让我用一个例子再来表示一下。好比说你是一个程序员,辛辛苦苦做出了一个功效,写了好几千行代码,上百个函数,终于通过了审核上线了。这个时刻,你的产物司理找到了你说,经由剖析我们发现上线的功效运行速率不达标,经常有请求超时,你能不能盘算一下每个函数运行的耗时,利便我们找到需要优化的地方?

这是一个异常合理的请求,但想想看你写了上百个函数,若是每一个函数都要手动添加时间盘算,这要写若干代码?万一哪个函数不小心改错了,你又得逐一检查,而且若是要求严酷的话你还得为每一个函数专门写一个单元测试……

我想,正常的程序员应该都市抗拒这个需求。

然则有了装饰器就很简朴了,我们可以实现一个盘算函数耗时的装饰器,然后我们只需要给每一个函数加上注解就好了。

import time
from functools import wraps
def timethis(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(func.__name__, end-start)
        return result
    return wrapper

这也是装饰器最大的用途,可以在不修改函数内部代码的前提下,为它包装一些分外的功效。

元信息

我们之前说过装饰器的本质是高阶函数,以是我们也可以和高阶函数一样来挪用装饰器,好比下面这样:

def exp(a, b, c='3', d='f'):
    print(a, b, c, d)


args = [13]
dt = {'c'4'd'5}

f = wrapexp(exp)
f(*args, **dt)

这样的方式获得的效果和使用注解是一样的,也就是说我们加上注解的本质实在就是挪用装饰器返回一个新的函数。

既然和高阶函数是一样的,那么就带来了一个问题,我们使用的实在已经不再是原函数了,而是一个由装饰器返回的新函数,虽然这个函数的功效和原函数一样,然则一些基础的信息实在已经丢失了。

好比我们可以打印出函数的name来做个实验:

正常的函数挪用__name__返回的都是函数的名称,然则当我们加上了装饰器的注解之后,就会发生变化,同样,我们输出加上了装饰器注解之后的效果:

我们会发现输出的效果变成了wrapper,这是由于我们实现的装饰器内部的函数叫做wrapper。不仅仅是__name__,函数内部另有许多其他的基本信息,好比纪录函数内形貌的__doc__,__annotations__等等,这些基本信息被称为是元信息,这些元信息由于我们使用注解发生了丢失。

有没有什么设施可以保留这些函数的元信息呢?

实在很简朴,Python当中为我们提供了一个专门的装饰器用来保留函数的元信息,我们只需要在实现装饰器的wrapper函数当中加上一个注解wraps即可。

def wrapexp(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print('this is a wrapper')
        func(*args, **kwargs)
    return wrapper

加上了这个注解之后,我们再来检查函数的元信息,会发现它和我们预期一致了。

总结

领会了Python中的装饰器之后,再来看之前我们用过的@property, @staticmethod等注解,想必都能明了,它们背后的实现实在也是装饰器。天真使用装饰器可以大大简化我们的代码,让我们的代码加倍规范简练,还能天真地实现一些特殊的功效。

装饰器的用法许多,今天先容的只是其中最基本的,在后续的文章当中,还会继续和人人分享它更多其他的用法。在文章最先的时刻我也说了,装饰器是Python进阶必学的技术之一。想要熟练掌握这门语言,天真运用,看懂大佬的源码,装饰器是必须会的器械。

希望人人都能有所收获,原创不易,厚颜求个赞和关注~

,

阳光在线

阳光在线www.baolonglxg.com(原诚信在线)现已开放阳光在线手机版下载。阳光在线游戏公平、公开、公正,用实力赢取信誉。

上一篇:鹤壁手机号码网:《赛博朋克2077》澳洲分级讲述 详细注释分级缘故原由

下一篇:皇冠体育网址:【消费专题】Vans 抽象灵鼠

网友评论