Python的装饰器小记

系统 1763 0

Python装饰器

1、简介
本质: Python的装饰器就是一个闭包。
目的: 简化代码操作

2、使用装饰器的原则:不改变被装饰函数的属性等性质

  • 使用中间人 g对象 帮助传递参数
  • 使用内层装饰器 @functools.wraps(view_func) 回复被装饰函数的属性等性质(举例2)

3、 举例1 :定义验证登录状态的装饰器

            
              
                # 使用中间人g对象作为装饰器和被装饰函数中的参数传递者
              
              
                from
              
               flask 
              
                import
              
               session
              
                ,
              
               jsonify
              
                ,
              
               g

              
                from
              
               myihome
              
                .
              
              utils
              
                .
              
              response_code 
              
                import
              
               RET

              
                import
              
               functools  
              
                # python的内置模块,存放函数工具
              
              
                # 闭包:外层函数一般就是定义为被装饰的函数(view_func(例如这里是:set_user_avatar))"的@外层函数"
              
              
                def
              
              
                login_required
              
              
                (
              
              view_func
              
                )
              
              
                :
              
              
                # 内层函数一般定义为wrapper,并且由于传递的参数不确定,使用*args, **kwargs待定
              
              
                # @functools.wraps(view_func)这个函数装饰器专门是用来装饰内层函数的,
              
              
                # 1参数:外层函数接受的参数,直接传给里面的就可以了,
              
              
                # 2意义:内层装饰器加上之后会改变一些特性:functools的wraps会将wrapper相关的属性和名字恢复为view_func的属性和名字,参考博客的例子2
              
              
    @functools
              
                .
              
              wraps
              
                (
              
              view_func
              
                )
              
              
                # 在写装饰器的时候需要习惯将这个内层装饰器补上,避免改变被装饰函数的特性
              
              
                def
              
              
                wrapper
              
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                :
              
              
                # 判断用户的登录状态
              
              
        user_id 
              
                =
              
               session
              
                .
              
              get
              
                (
              
              
                "user_id"
              
              
                )
              
              
                # 如果用户是登录的,执行视图函数
              
              
                if
              
               user_id 
              
                is
              
              
                not
              
              
                None
              
              
                :
              
              
                # g对象的应用,保存user_id,让其作为参数传递对象,在视图函数中可以通过g对象获取保存数据
              
              
            g
              
                .
              
              user_id 
              
                =
              
               user_id
            
              
                return
              
               view_func
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                else
              
              
                :
              
              
                # 如果未登录,返回未登录的信息
              
              
                return
              
               jsonify
              
                (
              
              errno
              
                =
              
              RET
              
                .
              
              SESSIONERR
              
                ,
              
               errmsg
              
                =
              
              
                "用户未登录"
              
              
                )
              
              
                return
              
               wrapper



              
                # 使用中间人g对象作为装饰器和被装饰函数中的参数传递者,g对象就是提供来保存数据的
              
              
                # 在一次请求之中如果涉及到多个函数请求参数的时候就可以使用g对象来传参数
              
              
@login_required

              
                def
              
              
                set_user_avatar
              
              
                (
              
              
                )
              
              
                :
              
              
                # 本来是可以直接操作session获取user_id的,
              
              
                # 但是使用的装饰器里面已经获取到了user_id,由装饰器的原则,不可能变成 def set_user_avatar(user_id):的,所以可以使用中间人g对象传递过来,不必重复操作一遍
              
              
                # user_id = session.get("user_id")
              
              
    user_id 
              
                =
              
               g
              
                .
              
              user_id
    
              
                pass
              
              
                # set_user_avatar() 的执行就是执行wrapper-> wrapper() 直接传递参数到wrapper()里面
              
            
          

4、 举例2: 内层装饰器 @functools.wraps(func) 的作用
①首先:未加上装饰器:

            
              
                def
              
              
                login_required
              
              
                (
              
              func
              
                )
              
              
                :
              
              
                def
              
              
                wrapper
              
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                :
              
              
                pass
              
              
                return
              
               wrapper


              
                def
              
              
                test
              
              
                (
              
              
                )
              
              
                :
              
              
                """test python"""
              
              
                pass
              
              
                print
              
              
                (
              
              test
              
                .
              
              __name__
              
                )
              
              
                print
              
              
                (
              
              test
              
                .
              
              __doc__
              
                )
              
            
          

Python中万物皆对象,直接打印出函数test()的名字和说明文档:

            
              test
test python

            
          

②加上装饰器:

            
              
                def
              
              
                login_required
              
              
                (
              
              func
              
                )
              
              
                :
              
              
                def
              
              
                wrapper
              
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                :
              
              
                pass
              
              
                return
              
               wrapper

@login_required

              
                def
              
              
                test
              
              
                (
              
              
                )
              
              
                :
              
              
                """test python"""
              
              
                pass
              
              
                # test -> wrapper :执行test(), 实质是执行wrapper()
              
              
                print
              
              
                (
              
              test
              
                .
              
              __name__
              
                )
              
              
                # wrapper.__name__
              
              
                print
              
              
                (
              
              test
              
                .
              
              __doc__
              
                )
              
              
                # wrapper.__doc__
              
            
          

打印的结果为:

            
              wrapper
None

            
          

可见已经改变test()的属性了,违反了装饰器的原则。
③加上内层函数装饰器:

            
              
                import
              
               functools


              
                def
              
              
                login_required
              
              
                (
              
              func
              
                )
              
              
                :
              
              
    @functools
              
                .
              
              wraps
              
                (
              
              func
              
                )
              
              
                def
              
              
                wrapper
              
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                :
              
              
                pass
              
              
                return
              
               wrapper
    
@login_required

              
                def
              
              
                test
              
              
                (
              
              
                )
              
              
                :
              
              
                """test python"""
              
              
                pass
              
              
                # test -> wrapper
              
              
                print
              
              
                (
              
              test
              
                .
              
              __name__
              
                )
              
              
                # wrapper.__name__
              
              
                print
              
              
                (
              
              test
              
                .
              
              __doc__
              
                )
              
              
                # wrapper.__doc__
              
            
          

打印结果为:

            
              test
test python

            
          

可见被装饰函数的属性被恢复了。

参考代码及项目URL:
https://github.com/too-hoo/myiHome/blob/master/myihome/utils/commons.py


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论