• 我终于弄懂了Python的装饰器(一)


    此系列文档:

    1. 我终于弄懂了Python的装饰器(一)

    2. 我终于弄懂了Python的装饰器(二)

    3. 我终于弄懂了Python的装饰器(三)

    4. 我终于弄懂了Python的装饰器(四)

    一、装饰器基础(什么是装饰器)

    Python的函数是对象

    要了解装饰器,您必须首先了解函数是Python中的对象。这具有重要的联系。

    让我们来看一个简单的例子:

    def shout(word="yes"):
        return word.capitalize()+"!"
    
    print(shout())
    # 输出 : 'Yes!'
    
    # 作为一个对象,您可以像其他对象一样将函数赋给变量
    scream = shout
    
    #注意我们不使用括号:我们没有调用函数
    #我们将函数“shout”放入变量“scream”。
    #这意味着您可以从“scream”中调用“shout”:
    
    print(scream())
    # 输出: 'Yes!'
    
    #除此之外,这意味着您可以删除旧名称'shout',该功能仍可从'scream'访问
    
    del shout
    
    try:
        print(shout())
    except NameError as e:
        print(e)
        #输出: "name 'shout' is not defined"
    
    print(scream())
    # 输出: 'Yes!'
    

    请记住这一点,我们将在不久后回头再说。

    Python函数的另一个有趣特性是可以在另一个函数中定义它们!

    def talk():
    
        # 您可以在“talk”中动态定义一个函数...
        def whisper(word="yes"):
            return word.lower()+"..."
    
        # ...并且可以立马使用它。
        print(whisper())
    
    #您每次调用“talk”,都会定义“whisper”,然后在“talk”中调用“whisper”。
    
    talk()
    # 输出: 
    # "yes..."
    
    # 但是"whisper"不存在"talk"定义以外的地方:
    
    try:
        print(whisper())
    except NameError as e:
        print(e)
        #输出 : "name 'whisper' is not defined"
    

    函数参考

    OK,应该还在看吧?现在开始有趣的部分...

    您已经看到函数是对象。
    因此,函数:

    • 可以分配给变量
    • 可以在另一个函数中定义

    这意味着一个函数可以return另一个功能

    def getTalk(kind="shout"):
    
        # 我们顶一个即时的函数
        def shout(word="yes"):
            return word.capitalize()+"!"
    
        def whisper(word="yes") :
            return word.lower()+"...";
    
        # 然后我们返回它
        if kind == "shout":
            #我们不使用“()”,所以我们没有调用函数,我们正在返回这个函数对象
            return shout  
        else:
            return whisper
    
    #获取函数并将其分配给变量: "talk"
    talk = getTalk()      
    
    #您可以看到“talk”是一个函数对象:
    print(talk)
    #输出 : <function shout at 0xb7ea817c>
    
    #函数对象返回的内容:
    print(talk())
    #输出 : Yes!
    
    #如果您感到困惑,甚至可以直接使用它:
    print(getTalk("whisper")())
    #outputs : yes...
    

    还有更多的内容!

    如果可以return一个函数,则可以将其中一个作为参数传递:

    def doSomethingBefore(func): 
        print("I do something before then I call the function you gave me")
        print(func())
    
    doSomethingBefore(scream)
    #输出: 
    #I do something before then I call the function you gave me
    #Yes!
    

    好吧,您只具备了解装饰器所需的所有信息。
    您会看到,装饰器是“包装器(wrappers)”,这意味着它们使您可以在装饰函数之前和之后执行代码,而无需修改函数本身的代码内容。

    手工进行装饰

    您将知道如何进行手动操作:

    #装饰器是讲另外一个函数作为参数的函数
    def my_shiny_new_decorator(a_function_to_decorate):
    
        # 在内部,装饰器动态定义一个函数:包装器(wrappers)。
        # 此功能将被包装在原始功能的外部,以便它可以在代码之前和之后执行代码。
        def the_wrapper_around_the_original_function():
    
            # 在调用原始函数之前,将要执行的代码放在此处
            print("Before the function runs")
    
            #在此处调用函数(使用括号)
            a_function_to_decorate()
    
            # 在调用原始函数后,将要执行的代码放在此处
            print("After the function runs")
    
        #至此,“a_function_to_decorate”从未执行过。
        #我们返回刚刚创建的包装函数。
        #包装器包含函数和在代码之前和之后执行的代码。随时可以使用!
        return the_wrapper_around_the_original_function
    
    #现在,假设您创建了函数,但是不想再修改的函数。
    def a_stand_alone_function():
        print("I am a stand alone function, don't you dare modify me")
    
    a_stand_alone_function() 
    #输出: I am a stand alone function, don't you dare modify me
    
    #所以,您可以装饰它以扩展其行为。
    #只需将其传递给装饰器,它将动态地包装在
    #您想要的任何代码中,并为您返回准备使用的新功能:
    
    a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function)
    a_stand_alone_function_decorated()
    
    #输出:
    #Before the function runs
    #I am a stand alone function, don't you dare modify me
    #After the function runs
    

    现在,您可能希望每次调用a_stand_alone_functiona_stand_alone_function_decorated都调用它。
    这很简单,只需a_stand_alone_function用以下方法返回的函数覆盖my_shiny_new_decorator

    a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function)
    a_stand_alone_function()
    #输出:
    #Before the function runs
    #I am a stand alone function, don't you dare modify me
    #After the function runs
    
    #这正是装饰器的工作!
    

    装饰器神秘化

    这里展示一下使用装饰器的语法:

    @my_shiny_new_decorator
    def another_stand_alone_function():
        print("Leave me alone")
    
    another_stand_alone_function()  
    #输出:  
    #Before the function runs
    #Leave me alone
    #After the function runs
    

    是的,仅此而已。@decorator只是实现以下目的的捷径:

    another_stand_alone_function = my_shiny_new_decorator(another_stand_alone_function)
    

    装饰器只是装饰器设计模式的pythonic变体。
    Python中嵌入了几种经典的设计模式来简化开发(例如迭代器)。

    当然,您可以累加装饰器:

    def bread(func):
        def wrapper():
            print("</''''''>")
            func()
            print("<\______/>")
        return wrapper
    
    def ingredients(func):
        def wrapper():
            print("#tomatoes#")
            func()
            print("~salad~")
        return wrapper
    
    def sandwich(food="--ham--"):
        print(food)
    
    sandwich()
    #输出: --ham--
    sandwich = bread(ingredients(sandwich))
    sandwich()
    #输出:
    #</''''''>
    # #tomatoes#
    # --ham--
    # ~salad~
    #<\______/>
    

    使用Python装饰器语法:

    @bread
    @ingredients
    def sandwich(food="--ham--"):
        print(food)
    
    sandwich()
    #outputs:
    #</''''''>
    # #tomatoes#
    # --ham--
    # ~salad~
    #<\______/>
    

    您设置装饰器事项的顺序是很重要的,如::

    @ingredients
    @bread
    def strange_sandwich(food="--ham--"):
        print(food)
    
    strange_sandwich()
    #outputs:
    ##tomatoes#
    #</''''''>
    # --ham--
    #<\______/>
    # ~salad~
    

    本文首发于BigYoung小站

  • 相关阅读:
    列表元素的删,添,复制
    序列的通用操作
    列排(list)排序
    列表(list)
    str的常用操作
    复制/etc/profile至/tmp/目录,用查找替换命令删除/tmp/profile文件中的行首的空白字符;在vim中设置tab缩进为4个字符
    Linux上的文件管理类命令都有那些,其中常用的使用方法及相关示例演示
    总结软连接和硬连接区别,并用实例操作
    文件的元信息有那些,分别表示什么含义,如何查看?如何修改文件的时间戳信息?
    Linux发行版的系统目录名称命名规则以及用途
  • 原文地址:https://www.cnblogs.com/bigyoung/p/13260727.html
Copyright © 2020-2023  润新知