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
          


 
					 
					