专栏首页BigYoung小站我终于弄懂了Python的装饰器(二)

我终于弄懂了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.\n"
                  "I can access all the variables\n"
                  "\t- from the decorator: {0} {1}\n"
                  "\t- from the function call: {2} {3}\n"
                  "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小站(bigyoungs),作者:Young文人

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-07-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Linux忘记 root密码的解决办法

    我管理的VM EXSI 6.5虚拟机上,搭建有一个CentOS的系统,因为申请资源的管理者长时间不用,忘记了root的登录密码,所以我就验证了以下的教程,亲测可...

    BigYoung小站
  • 登录微软账号的Windows电脑如何远程?

    一般情况下,我们都使用的是Windows电脑的本地账户。但是随着Windows 10的推广,现在微软也开始主推微软账号登录Windows电脑了。

    BigYoung小站
  • 使用ADMT和PES实现window AD账户跨域迁移-PES的安装

    在安装了 ADMT 的服务器上,(首发:bigyoung.cn)创建一个共享文件夹,我们将在其中放置密码的加密密钥。

    BigYoung小站
  • HTML5中的Web Notification桌面通知

    大家在做一些浏览器端的聊天功能的时候,或者在一些网站跟在线客服咨询的时候,会看到一些消息通知的提示,常见的有浏览器标签页的闪烁和屏幕右侧的消息通知。本篇博客就在...

    用户1174387
  • Jquer学习之jQuery(function(){})与(function(){})(jQuery)之间的区别

    Jquery是优秀的Javascrīpt框架。我们现在来讨论下在 Jquery 中两个页面载入后执行的函数。 $(document).ready(functio...

    郑小超.
  • jQuery源码研究:为jQ对象扩展的一些工具方法(上)

    上一章,讨论的是jQuery对象及其原型上的extend()方法,在源码中,实现了支持开发者自行扩展新方法的功能,但其实jQuery也通过对extend()传入...

    前端_AWhile
  • Love beautiful code? We do too.

    Laravel是一个有着美好前景的年轻框架,它的社区充满着活力,同时提供了完整而清晰的文档,而且为快速、安全地开发现代应用提供了必要的功能。

    貟王軍
  • C/C++宏之#与##

    Qt君
  • Python中namedtuple使用

    致Great
  • #凯哥讲数智化#从DataOps看CDO/CIO/CTO的分工

    “ 越来越多的企业配置两个乃至三个技术管理者角色,首席信息官CIO,首席数据官CDO,乃至首席技术官CTO。

    凯哥

扫码关注云+社区

领取腾讯云代金券