• 为什么说想到Python中的装饰器是天才


    为什么说想到Python中的装饰器是天才

    只需一个@符号就能分析、测试和重复使用你的代码

    alt

    带着魔杖的仙女在Python代码中飞舞

    软件中有没有什么是神奇的小魔法? 有,装饰器却非常接近!

    如果说有一件事使Python难以置信地成功,那就是它的可读性。其他一切都取决于此:如果代码不可读,就很难维护。那么它也对初学者不友好--一个被不可读的代码弄得晕头转向的新手,有一天也不会尝试写自己的代码。

    在装饰器出现之前,Python 已经是可读的,并且对初学者友好。但随着语言开始被用于越来越多的事情,Python 开发者感到需要越来越多的功能,同时又不至于杂乱无章,使代码无法阅读。

    装饰器是一个完美实现功能的典型例子。它确实需要花点时间来理解,但这是值得的。当你开始使用它们时,你会注意到它们不会使事情过度复杂化,并使你的代码变得整洁而时髦。

    在其他事情之前:高阶函数

    简而言之,装饰器是处理高阶函数的一种整洁的方式。所以让我们先来看看这些

    返回函数的函数 假设你有一个函数,greet() - 它向你传递的任何对象致意

    假设你有另一个函数,simon() - 它在适当的地方插入 "Simon"

    我们怎样才能把这两个函数结合起来呢? 在你看下面的内容之前先想一想。

    def greet(name):
        return f"Hello, {name}!"
        
    def simon(func):
        return func("Simon")
        
    simon(greet)
    The output is 'Hello, Simon!'.
    • 1

    输出是 "你好,西蒙!"

    希望这对你了解函数返回一个函数有意义!

    当然,我们可以直接调用greet("Simon")。然而,重点是我们可能想把 "Simon "放到许多不同的函数中。如果我们不使用 "Simon",而是使用更复杂的东西,我们可以通过把它打包到simon()这样的函数中来节省大量的代码行。

    函数中的函数

    我们也可以在其他函数中定义函数。这一点很重要,因为装饰器也会这样做。如果没有装饰器,它看起来像这样。

    下面的函数是接受参数 gpa 成绩,如果是‘yes’或大于‘90’分则调用函数 congrats() 否则,调用函数 encourage()

    #练习修改

    def respect(gpa):
        def congrats():
            return "Congrats, Your gpa is excellent!"

        def encourage():
            return "You're have change to try again"

        if gpa == "yes"
            return congrats()
        else
            return encourage()

    gpa = '91' #'python'
    gpa = "no"

    print(f"{gpa},{respect(gpa)}")

    #output:
    no,You're have change to try again
    • 1

    另外找时间讲一个意外:

    print(gpa > '90')
    # 注意字符串的比较结果意外吧?
    • 1

    函数 respect() 返回一个函数; respect("yes") 返回祝贺函数, respect("brother") (或其他参数代替 "brother")返回鼓励函数。

    要调用这些函数,请输入 respect("yes") 和 respect("brother"),就像普通函数一样。

    明白了吗?那么你就可以为装饰者做好准备了!

    alt 代码是美丽的书呆子

    在电脑屏幕前显示的女人

    Python装饰器的ABC 带有@符号的函数 让我们尝试一下前面两个概念的组合:一个函数接收另一个函数,并定义一个函数。听起来很匪夷所思?考虑一下这个。


    def startstop(func):
        def wrapper():
            print("开始...")
            func()
            print("完成了!")
        返回包装器
    def roll():
        print("在地上打滚,笑死人了 XD")
        
        
    roll()
    #OUPUT:

    Starting...
    Rolling on the floor laughing XD
    Finished!
    • 1

    最后一行确保我们不再需要调用

    startstop(roll)()
    • 1

    roll()就足够了。你知道这个调用的输出是什么吗?如果你不确定的话,就自己试试吧!

    现在,作为一个非常好的替代方案,我们可以在定义startstop()之后直接插入这个。

    @startstop
    def roll():
        print("在地板上笑着打滚 XD")
        
    • 1

    这样做是一样的,但是在开始时就把roll()和startstop()粘在一起了。

    增加了灵活性

    为什么会有这样的作用?这不是要消耗和以前一模一样多的代码行吗?

    在这种情况下,是的。但是一旦你要处理稍微复杂的东西,它就会变得非常有用。这一次,你可以把所有的装饰器,即上面的def startstop()部分移到它自己的模块里。

    也就是说,你把它们写进一个叫做decorators.py的文件,然后在你的主文件中写上类似这样的内容。


    from decorators import startstop
    @startstop
    def roll():
        print("在地上打滚,笑死我了XD")
        
    • 1

    原则上,你可以不使用

    decorators.py
    • 1

    来做这个。但这种方式使生活更简单,因为你不必再处理嵌套函数和无休止的括号计算了。

    你也可以同时再嵌套其他装饰器。譬如计算函数执行时间的 exectime


    from decorators import startstop, exectime
    @exectime
    @startstop
    def roll():
        print("在地上打滚,笑死人了 XD")
        
    • 1

    注意,我们还没有定义exectime(),但你会在看到它。它是一个可以测量Python中一个过程所需时间的函数。这样的嵌套相当于这样的一行。

    导入time时间库

    import time

    # 用来计算持续时间的装饰器
    # 被任何函数占用的时间。

    def exectime(func):
        # 在inner1内添加参数。
        # 如果函数需要任何参数。
        # 可以像这样添加。
        def inner1(*args, **kwargs):
            # 储存函数执行前的时间
            begin = time.time()

            func(*args, **kwargs)

            # 储存函数执行后的时间
            end = time.time()
            print("Total time taken in : " , func.__name__, end - begin)

        return inner1
    • 1

    现在就可以正常运行了

    # 调用上面已经定义excetime函数!
    from decoratorsRoll import startstop, exectime  
    @exectime
    @startstop
    def roll():
        time.sleep(3)
        print("Rolling on the floor laughing XD")
    roll()

    roll = exectime(startstop(roll))
    print(roll())

    Starting...
    Rolling on the floor laughing XD
    Finished!
    Total time taken in :  wrapper 3.0007543563842773

    • 1

    括号内的计数开始了! 想象一下,你有五六个这样的函数相互嵌套在一起。装饰器的符号不是比这种嵌套的混乱更容易阅读吗?

    你甚至可以在接受参数的函数上使用装饰器。现在想象一下,在上面那行中有几个参数,你的混乱就会完成。装饰器让它变得整齐划一。

    最后,你甚至可以向你的装饰器添加参数--比如@mydecorator(argument)。是的,你可以不用装饰器来做这一切。但是,我祝愿你在三周后重读你的无装饰器的代码时,会有很多乐趣......

    alt

    女人站在桌子上,上面放着电脑、浓缩咖啡杯和花瓶

    装饰者使一切变得更容易

    应用:装饰者切入的地方 现在,我希望能说服你,装饰器使你的生活轻松三倍,让我们看看一些经典的例子,在这些例子中,装饰器基本上是不可缺少的。

    测量执行时间 上面的写法稍作变化:time.perf_counter()

    假设我们有一个叫做waste time()的函数,我们想知道它需要多长时间执行完函数。那么,就用一个装饰器:

    import time
    def measuretime(func):
        def wrapper():
            starttime = time.perf_counter()
            func()
            endtime = time.perf_counter()
            print(f"Time needed: {endtime - starttime} seconds")
        return wrapper
        
    @measuretime
    def wastetime():
        sum([i**2 for i in range(1000000)])
    wastetime()

    • 1

    十几行代码,我们就完成了! 另外,你可以在任意多的函数上使用 measuretime()

    减缓代码速度

    有时你不想立即执行代码,而是要等待一段时间。这时,减速装饰器就派上用场了。

    import time
    def sleep(func):
        def wrapper():
            time.sleep(300)
            return func()
        return wrapper
    @sleep
    def wakeup():
        print("Get up! Your break is over.")
    wakeup()
    • 1

    调用wakeup()使得你可以休息5分钟,之后你的控制台会提醒你回去工作。

    测试和调试

    假设你有一大堆不同的函数,你在不同的阶段调用,而你对什么时候被调用失去了概览。通过对每个函数定义的简单装饰器,你可以使其更加清晰。就像这样。

    def debug(func):
        def wrapper():
            print(f"Calling {func.__name__}")
        return wrapper
    @debug
    def scare():
        print("Boo!")
    scare()

    • 1

    这里有一个更详细的例子。不过要注意的是,要理解这个例子,你必须检查如何用参数来装饰函数。不过,这还是值得一读的!

    重用代码

    这一点不言而喻。如果你已经定义了一个函数decorator(),你就可以在你的代码中到处撒上@decorator。说实话,我认为没有比这更简单的了。

    处理登录

    如果你有一些功能只有在用户登录后才能访问,使用装饰器也是相当容易的。我会让你参考完整的例子,但原理很简单:首先你定义一个类似login_required()的函数。在任何需要登录的函数定义之前,你弹出@login_required

    我想说,这让调用变得很简单!

    语法糖--为什么Python是如此的甜蜜

    Python有一个很大的诱惑力:它是如此容易理解,即使你不是一个受过训练的计算机科学家,而只是想让事情运转,帮你快速上手解决问题!

    如果C++是一个橙子,那么Python就是一个菠萝:营养相似,但甜度要高三倍。装饰器只是其中的一个因素。

    但我希望你已经明白了为什么它是如此大的一个甜味因素。合成糖为你的生活增添一些乐趣!这就是合成糖。没有健康风险,除了让你的眼睛粘在屏幕上。

    我祝愿你有很多甜蜜的代码!

    本文由 mdnice 多平台发布

  • 相关阅读:
    意向不到的Dubug妙招
    28、iNeRF
    自从测试部新来了个00后卷王,老油条感叹真干不过,但是...
    全面了解链上身份之Web3社交及相关项目
    疫情防控系统怎么选?还是国产化的靠谱
    【深度学习】实验1布置:Softmax实现手写数字识别
    js——arguments的使用
    跨平台Markdown编辑软件Typora mac中文版功能介绍
    java特种兵读书笔记(3-5)——java程序员的OS之OOM
    维格云代码块入门教程
  • 原文地址:https://blog.csdn.net/qq_40523298/article/details/127549459