zoukankan      html  css  js  c++  java
  • 我终于弄懂了Python的装饰器(二)

    此系列文档:

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

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

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

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

    二、装饰器的高级用法

    将参数传递给装饰函数

    #它不是黑魔法,只是给包装(wrapper)传递参数:
    
    def a_decorator_passing_arguments(function_to_decorate):
        def a_wrapper_accepting_arguments(arg1, arg2):
            print("I got args! Look: {0}, {1}".format(arg1, arg2))
            function_to_decorate(arg1, arg2)
        return a_wrapper_accepting_arguments
    
    #因为当您调用装饰器返回的函数时,调用的包装器(wrapper),将参数传递给被包装器包装的函数
    
    @a_decorator_passing_arguments
    def print_full_name(first_name, last_name):
        print("My name is {0} {1}".format(first_name, last_name))
    
    print_full_name("Peter", "Venkman")
    # 输出:
    #I got args! Look: Peter Venkman
    #My name is Peter Venkman
    

    将参数传递给装饰器

    关于将参数传递给装饰器本身,您怎么认为?

    因为装饰器必须接受一个函数作为参数,所以这可能会有些别扭。

    因此,您不能将装饰函数的参数直接传递给装饰器。

    在寻求解决方案之前,让我们写一些提醒:

    #装饰器是普通函数
    def my_decorator(func):
        print("I am an ordinary function")
        def wrapper():
            print("I am function returned by the decorator")
            func()
        return wrapper
    
    # 因此,你可以调用它,而不用 "@"
    
    def lazy_function():
        print("zzzzzzzz")
    
    decorated_function = my_decorator(lazy_function)
    #输出: I am an ordinary function
    
    # 它输出了 "I am an ordinary function", 因为你只是调用了装饰器,而没有调用函数:
    # 这里没有什么神奇的地方,使用'@'
    
    @my_decorator
    def lazy_function():
        print("zzzzzzzz")
    
    #outputs: I am an ordinary function
    

    结果一样。
    my_decorator”被调用了。
    因此,当您使用时@my_decorator,您要告诉Python,通过变量来调用my_decorator标记了的函数。

    def decorator_maker():
    
        print("I make decorators! I am executed only once: "
              "when you make me create a decorator.")
    
        def my_decorator(func):
    
            print("I am a decorator! I am executed only when you decorate a function.")
    
            def wrapped():
                print("I am the wrapper around the decorated function. "
                      "I am called when you call the decorated function. "
                      "As the wrapper, I return the RESULT of the decorated function.")
                return func()
    
            print("As the decorator, I return the wrapped function.")
    
            return wrapped
    
        print("As a decorator maker, I return a decorator")
        return my_decorator
    
    #让我们新建一个装饰器
    new_decorator = decorator_maker()       
    #输出:
    #I make decorators! I am executed only once: when you make me create a decorator.
    #As a decorator maker, I return a decorator
    
    # 让我们装饰这个函数
    def decorated_function():
        print("I am the decorated function.")
    
    decorated_function = new_decorator(decorated_function)
    #输出:
    #I am a decorator! I am executed only when you decorate a function.
    #As the decorator, I return the wrapped function
    
    # 让我们调用这个函数
    decorated_function()
    
    #输出:
    #I am the wrapper around the decorated function. I am called when you call the decorated function.
    #As the wrapper, I return the RESULT of the decorated function.
    #I am the decorated function.
    

    毫不奇怪,跟我们前边演示的内容一样。

    让我们再做一次完全一样的事情,但是这次我们跳过所有讨厌的中间变量:

    def decorated_function():
        print("I am the decorated function.")
    decorated_function = decorator_maker()(decorated_function)
    #输出:
    #I make decorators! I am executed only once: when you make me create a decorator.
    #As a decorator maker, I return a decorator
    #I am a decorator! I am executed only when you decorate a function.
    #As the decorator, I return the wrapped function.
    
    # Finally:
    decorated_function()    
    #输出:
    #I am the wrapper around the decorated function. I am called when you call the decorated function.
    #As the wrapper, I return the RESULT of the decorated function.
    #I am the decorated function.
    

    让我们把它变的更精简:

    @decorator_maker()
    def decorated_function():
        print("I am the decorated function.")
    #输出:
    #I make decorators! I am executed only once: when you make me create a decorator.
    #As a decorator maker, I return a decorator
    #I am a decorator! I am executed only when you decorate a function.
    #As the decorator, I return the wrapped function.
    
    #最终: 
    decorated_function()    
    #输出:
    #I am the wrapper around the decorated function. I am called when you call the decorated function.
    #As the wrapper, I return the RESULT of the decorated function.
    #I am the decorated function.
    

    嘿,你看到了吗?我们使用了带有“ @”语法的函数调用!

    因此,回到带有参数的装饰器。
    如果我们可以使用函数即时生成装饰器,则可以将参数传递给该函数,对吗?

    def decorator_maker_with_arguments(decorator_arg1, decorator_arg2):
    
        print("I make decorators! And I accept arguments: {0}, {1}".format(decorator_arg1, decorator_arg2))
    
        def my_decorator(func):
            #这里传递的参数是闭包的。
            #如果您对封包感到不舒服,可以忽略这点。
            print("I am the decorator. Somehow you passed me arguments: {0}, {1}".format(decorator_arg1, decorator_arg2))
    
                #不要混淆装饰器参数和函数参数!        
            def wrapped(function_arg1, function_arg2) :
                print("I am the wrapper around the decorated function.
    "
                      "I can access all the variables
    "
                      "	- from the decorator: {0} {1}
    "
                      "	- from the function call: {2} {3}
    "
                      "Then I can pass them to the decorated function"
                      .format(decorator_arg1, decorator_arg2,
                              function_arg1, function_arg2))
                return func(function_arg1, function_arg2)
    
            return wrapped
    
        return my_decorator
    
    @decorator_maker_with_arguments("Leonard", "Sheldon")
    def decorated_function_with_arguments(function_arg1, function_arg2):
        print("I am the decorated function and only knows about my arguments: {0}"
               " {1}".format(function_arg1, function_arg2))
    
    decorated_function_with_arguments("Rajesh", "Howard")
    #输出:
    #I make decorators! And I accept arguments: Leonard Sheldon
    #I am the decorator. Somehow you passed me arguments: Leonard Sheldon
    #I am the wrapper around the decorated function. 
    #I can access all the variables 
    #   - from the decorator: Leonard Sheldon 
    #   - from the function call: Rajesh Howard 
    #Then I can pass them to the decorated function
    #I am the decorated function and only knows about my arguments: Rajesh Howard
    

    记住它:带参数的装饰器,可以将变量作为参数:

    c1 = "Penny"
    c2 = "Leslie"
    
    @decorator_maker_with_arguments("Leonard", c1)
    def decorated_function_with_arguments(function_arg1, function_arg2):
        print("I am the decorated function and only knows about my arguments:"
               " {0} {1}".format(function_arg1, function_arg2))
    
    decorated_function_with_arguments(c2, "Howard")
    #输出:
    #I make decorators! And I accept arguments: Leonard Penny
    #I am the decorator. Somehow you passed me arguments: Leonard Penny
    #I am the wrapper around the decorated function. 
    #I can access all the variables 
    #   - from the decorator: Leonard Penny 
    #   - from the function call: Leslie Howard 
    #Then I can pass them to the decorated function
    #I am the decorated function and only know about my arguments: Leslie Howard
    

    如您所见,您可以像任何函数传递参数一样传递参数给装饰器。
    您甚至可以根据需要使用*args, **kwargs
    但是请记住,装饰器被调用一次,仅在Python导入脚本时。之后,您将无法动态设置参数。
    当您执行“ import x”时,该函数已经被修饰,因此您无法进行任何更改。

    本文首发于BigYoung小站

  • 相关阅读:
    第17章—前端分页(Bootstrap-Table)
    第16章—日志(slf4j&logback)
    第15章—数据库连接池(DBCP2)
    第14章—数据库连接池(C3P0)
    第13章—数据库连接池(Druid)
    第00章—IDEA
    第12章—整合Redis
    第11章—常用注解(持续更新中)
    获取图片的宽高
    button按钮文字超出范围后省略号位置设置
  • 原文地址:https://www.cnblogs.com/bigyoung/p/13266595.html
Copyright © 2011-2022 走看看