美文网首页
python装饰器听了N次也没印象,读完这篇你就懂了

python装饰器听了N次也没印象,读完这篇你就懂了

作者: 蒸熟的土豆 | 来源:发表于2020-09-04 14:00 被阅读0次

    装饰器其实一直是我的一个"老大难"。这个知识点就放在那,但是拖延症。。。

    其实在平常写写脚本的过程中,这个知识点你可能用到不多

    但在面试的时候,这可是一个高频问题。

    一、什么是装饰器

    所谓的装饰器,其实就是通过装饰器函数,来修改原函数的一些功能,使得原函数不需要修改。

    这一句话理解起来可能没那么轻松,那先来看一个"傻瓜"函数。

    放心,绝对不是"Hello World"!

    defhello():print("你好,装饰器")

    肿么样,木骗你吧? 哈哈,这个函数不用运行相信大家都知道输出结果:"你好,装饰器"。

    那如果我想让hello()函数再实现个其他功能,比如多打印一句话。

    那么,可以这样"增强"一下:

    defmy_decorator(func):defwrapper():print("这是装饰后具有的新输出")        func()returnwrapperdefhello():print("你好,装饰器")hello = my_decorator(hello)hello()

    运行结果:

    这是装饰后具有的新输出你好,装饰器[Finishedin0.1s]

    很显然,这个"增强"没啥作用,但是可以帮助理解装饰器。

    当运行最后的hello()函数时,调用过程是这样的:

    hello = my_decorator(hello)中,变量hello指向的是my_decorator()

    my_decorator(func)中返回的wrapper(),传参是hello,因此又会调用到原函数hello()

    于是乎,先打印出了wrapper()函数里的,然后才打印出hello()函数里的

    那上述代码里的my_decorator()就是一个装饰器。

    它改变了hello()的行为,但是并没有去真正的改变hello()函数的内部实现。

    但是,python一直以"优雅"被人追捧,而上述的代码显然不够优雅。

    二、优雅的装饰器

    所以,想让上述装饰器变得优雅,可以这样写:

    defmy_decorator(func):defwrapper():print("这是装饰后具有的新输出")        func()returnwrapper@my_decoratordefhello():print("你好,装饰器")hello()

    这里的@my_decorator就相当于旧代码的hello = my_decorator(hello),@符号称为语法糖。

    那如果还有其他函数也需要加上类似的装饰,直接在函数的上方加上@my_decorator就可以,大大提高函数

    的重复利用与可读性。

    defmy_decorator(func):defwrapper():print("这是装饰后具有的新输出")        func()returnwrapper@my_decoratordefhello():print("你好,装饰器")@my_decoratordefhello2():print("你好,装饰器2")hello2()

    输出:

    这是装饰后具有的新输出你好,装饰器2[Finishedin0.1s]

    三、带参数的装饰器

    1. 单个参数

    上面的只是一个非常简单的装饰器,但是实际场景中,很多函数都是要带有参数的,比如hello(people_name)。

    其实也很简单,要什么我们就给什么呗,直接在对应装饰器的wrapper()上,加上对应的参数:

    defmy_decorator(func):defwrapper(people_name):print("这是装饰后具有的新输出")        func(people_name)returnwrapper@my_decoratordefhello(people_name):print("你好,{}".format(people_name))hello("张三")

    输出:

    这是装饰后具有的新输出你好,张三[Finishedin0.1s]

    2. 多个参数

    但是还没完,这样虽然简单,但是随之而来另一个问题:因为并不是所有函数参数都是一样的,

    当其他要使用装饰器的函数参数不止这个一个肿么办?比如:

    @my_decoratordefhello3(speaker, listener):print("{}对{}说你好!".format(speaker, listener))

    没关系,在python里,*args和**kwargs表示接受任意数量和类型的参数,所以我们可以这样

    写装饰器里的wrapper()函数:

    defmy_decorator(func):defwrapper(*args, **kwargs):print("这是装饰后具有的新输出")        func(*args, **kwargs)returnwrapper@my_decoratordefhello(people_name):print("你好,{}".format(people_name))@my_decoratordefhello3(speaker, listener):print("{}对{}说你好!".format(speaker, listener))hello("老王")print("------------------------")hello3("张三","李四")

    同时运行下hello("老王"),和hello3("张三", "李四"),看结果:

    这是装饰后具有的新输出你好,老王------------------------这是装饰后具有的新输出张三对李四说你好![Finishedin0.1s]

    3. 自定义参数

    上面2种,装饰器都是接收外来的参数,其实装饰器还可以接收自己的参数。

    比如,我加个参数来控制下装饰器中打印信息的次数:

    defcount(num):defmy_decorator(func):defwrapper(*args, **kwargs):foriinrange(num):                print("这是装饰后具有的新输出")                func(*args, **kwargs)returnwrapperreturnmy_decorator@count(3)defhello(people_name):print("你好,{}".format(people_name))hello("老王")

    注意,这里count装饰函数中的2个return.

    运行下,应该会出现3次:

    这是装饰后具有的新输出你好,老王这是装饰后具有的新输出你好,老王这是装饰后具有的新输出你好,老王[Finishedin0.1s]

    4. 内置装饰器@functools.wrap

    现在多做一步探索,我们来打印下下面例子中的hello()函数的元信息:

    defmy_decorator(func):defwrapper(*args, **kwargs):print("这是装饰后具有的新输出")        func(*args, **kwargs)returnwrapper@my_decoratordefhello(people_name):print("你好,{}".format(people_name))print(hello.__name__)#看下hello函数的元信息

    输出:

    wrapper

    这说明了,它不再是以前的那个 hello() 函数,而是被 wrapper() 函数取代了。

    如果我们需要用到元函数信息,那怎么保留它呢?这时候可以用内置装饰器@functools.wrap。

    importfunctoolsdefmy_decorator(func):    @functools.wraps(func)defwrapper(*args, **kwargs):print("这是装饰后具有的新输出")        func(*args, **kwargs)returnwrapper@my_decoratordefhello(people_name):print("你好,{}".format(people_name))print(hello.__name__)

    运行下:

    hello[Finishedin0.1s]

    好记性不如烂笔头,写一下理解一下会好很多。

    下面还分享类的装饰器,以及装饰器所用场景。

    在学习Python的过程中,往往因为没有资料或者没人指导从而导致自己不想学,可以看我主页哦 ,配套资料、python、pycharm安装包可以都有,不管是学习到哪个阶段的小伙伴都可以获取到自己相对应的资料,感谢支持!!!

    相关文章

      网友评论

          本文标题:python装饰器听了N次也没印象,读完这篇你就懂了

          本文链接:https://www.haomeiwen.com/subject/mlpzsktx.html