[Python小记] 装饰器怎么用 ?

装饰器的含义和作用:    

    装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。

    它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

    注意:本文重点介绍装饰器如何使用,如需详细学习装饰器原理,推荐刘志军老师的装饰器讲解

示例场景:

    公司后端同学已经写好了两个接口供前端小伙伴使用,这两个接口没有做任何限制,可以直接调用。有一天老大告诉后端的同学:从现在开始,你们开发的每个接口对外提供调用的时候都要做身份验证,使用user:passwd的方式;验证不通过就不允许调用接口。

     接口示例:

    def get_item_price(name):
        # todo: get data from your DB
        # eg:  data is stored in a dict now.
        _dict = {'apple': 9, 'banana': 6}

        return _dict[name]

    def get_item_num(name):
        # todo: get data from your DB
        # eg:  data is stored in a dict now.
        _dict = {'apple': 300, 'banana': 256}

        return _dict[name]

      接口的功能很简单,根据商品名查询对应商品的价格和存货数量。

      想要一劳永逸的给每个接口轻松实现user:passwd验证的话,装饰器是不二之选!下面是代码实现:

    #装饰器
    def verifier_decorator(func):

        def wrapper(user,passwd,*args,**kwargs):
            #todo: Read username and passwd from your DB and verify
            #eg: passport is stored in a _dict now.

            pass_dict = {'eli':'123','wang':'456'}

            if (user,passwd) in pass_dict.items():
                print('Success, Your passport has been verified!')
                return func(*args,**kwargs)
            else:
                print('Failed, Your passport is not verified!')
        return wrapper

    # 使用@语法糖给函数调用装饰器
    @verifier_decorator
    def get_item_price(name):
        # todo: get data from your DB
        # eg:  data is stored in a dict now.
        _dict = {'apple': 9, 'banana': 6}

        return _dict[name]

    @verifier_decorator
    def get_item_num(name):
        # todo: get data from your DB
        # eg:  data is stored in a dict now.
        _dict = {'apple': 300, 'banana': 256}

        return _dict[name]

    print(get_item_price('eli','13','apple'))
    #Failed, Your passport is not verified!
    #None

    print(get_item_num('wang','456','apple'))
    #Success, Your passport has been verified!
    # 300

        以上代码示例中,我在定义接口函数的时候只写了一个参数,而调用时传了三个参数却没有报错。

        是因为前两个参数被装饰器中的闭包函数接收了,定义接口的时候是这么写的:

    @verifier_decorator
    def get_item_num(name):

        这段代码等效于(把@那行注释,在调用接口前写上这行) :

    get_item_price = verifier_decorator(get_item_price)

        当实际调用的时候,此接口就非彼接口了,解释器真正执行的其实是装饰器中的闭包函数,所以调用的时候填多个参数也不会报错。可以理解为,装饰器取走了你定义的接口函数,又还了一个“一模一样”的函数给你。但这个过程中装饰器又干了点别的事情。【取走--原基础上添加其他代码--再还回】这一整个过程称为“装饰”。

        当然,实际上它并不会还回一个“一模一样”的函数给你,装饰的过程中,原函数的元信息会被闭包函数替换掉:

    def deco(func):
        def wrapper(name):
            '''I am wrapper'''
            return func(name)
        return wrapper

    @deco
    def print_name(name):
        '''I am func'''
        print(print_name.__doc__)
        print(print_name.__name__)
        print(name)
    print_name('eli')
    #I am wrapper
    # wrapper
    # eli

        你如果明白了刚才说的“装饰”过程,这个地方就很容易理解了。即:真正执行的函数是装饰器中的闭包函数(wrapper)!

        那应该如何保留原函数的元信息?

    from functools import wraps #<<<---
    def deco(func):
        @wraps(func)  #<<<---
        def wrapper(name):
            '''I am wrapper'''
            return func(name)
        return wrapper

    @deco
    def print_name(name):
        '''I am func'''
        print(print_name.__doc__)
        print(print_name.__name__)
        print(name)
    print_name('eli')
    #I am func
    # print_name
    # eli

        Python标准库中的functools的wraps方法会在装饰器运行的时候将原函数的元信息一同传递给闭包函数,进而使得原函数对象的所有信息得以保留。


声明:本文章为个人对技术的理解与总结,不能保证毫无瑕疵,接收网友的斧正。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值