zoukankan      html  css  js  c++  java
  • python——flask——装饰器

    python装饰器

      装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短,也更Pythonic(Python范儿)

    装饰器的作用:在不改变一个函数及其调用方式的基础上给一个函数增加功能

    案例:

      在不改变函数A和其调用方式的前提下给函数A增加计算其运行时间的功能

    import time
    
    def show_time(func):
        start_time=time.time()
        func()
        end_time=time.time()
        print('函数的运行时间为:%s'%(end_time-start_time))
    
    def A():
        time.sleep(1)   #延迟一秒
        print("这是函数A")
    
    
    if __name__=="__main__":
        A=show_time(A)
        A()

    但是这样会有一个问题

     造成这样问题的主要原因就是因为功能函数没有return返回值,所以我们返回A的内存地址

    import time
    
    def show_time(func):
        start_time=time.time()
        func()
        end_time=time.time()
        print('函数的运行时间为:%s'%(end_time-start_time))
        return fun
    def A():
        time.sleep(1)   #延迟一秒
        print("这是函数A")
    
    if __name__=="__main__":
        A=show_time(A)
        A()

    但是这样运行代码会发现,函数A执行了两次

     这个原因主要就是把函数A的内存地址传给了函数show_time,然后函数内执行了一次,打印,然后再把函数A的内存地址返回出去,但是下面赋值的时候,因为函数的优先及是大于赋值的,所以还会执行函数A

    这个问题怎么解决呢,就需要用函数嵌套了,在功能函数show_time中再嵌套一个函数(函数内部是可以调用函数外的参数)就行了,需要注意的是现在的变量A不是原来的变量A了,因为返回的是函数wrapper的内存地址,

    所以现在的A就是函数Weapper的内存地址

    import time
    
    def A():
        time.sleep(1)   #延迟一秒
        print("这是函数A")
    
    def show_time(func):
        def wrapper():
            start_time=time.time()
            func()
            end_time=time.time()
            print('函数的运行时间为:%s'%(end_time-start_time))
        return wrapper   #返回函数wrapper的内存地址
    if __name__=="__main__":
        A=show_time(A)
        A()
    View Code

    平民版:

      但是这样还多加了一行代码,我们怎么解决呢,我们就可以用到装饰器了,直接用@函数名的方式就能直接使用,需要注意的是功能函数必须要在函数之前,不然会找不到这个功能函数

    import time
    
    def show_time(func):
        def wrapper():
            start_time=time.time()
            func()
            end_time=time.time()
            print('函数的运行时间为:%s'%(end_time-start_time))
        return wrapper   #返回函数wrapper的内存地址
    @show_time    #  @show_time ==    A=show_time(A)
    def A():
        time.sleep(1)   #延迟一秒
        print("这是函数A")
    
    if __name__=="__main__":
        A()     #A=wrapper
    View Code

    普通版:

      当函数有返回值的时候,需要用一个变量来接收函数需要返回的参数,再将接收到的这个参数结果返回出去就行了

    import time
    
    def show_time(func):
        def wrapper():
            start_time=time.time()
            res=func()
            end_time=time.time()
            print('函数的运行时间为:%s'%(end_time-start_time))
            return res
        return wrapper   #返回函数wrapper的内存地址
    
    @show_time    #  @show_time ==    A=show_time(A)
    def A():
        time.sleep(1)   #延迟一秒
        print("这是函数A")
        return '%s的年龄为%s'%(name,age)
    
    if __name__=="__main__":
        print(A())   #现在的A=wrapper
    函数有返回值

    进阶版:

      当函数有参数的时候,因为通过装饰器以后,运行的函数A是功能函数中的wrapper函数,所以直接给函数wrapper写入参数(*args(位置参数),**kwargs(关键字参数:key,vlaue的形式))就行了,然后将参数写入外层函数接收到的函数A

    来处理就行了

    import time
    
    def show_time(func):
        def wrapper(*args,**kwargs):
            start_time=time.time()
            res=func(*args,**kwargs)
            end_time=time.time()
            print('函数的运行时间为:%s'%(end_time-start_time))
            return res
        return wrapper   #返回函数wrapper的内存地址
    
    @show_time    #  @show_time ==    A=show_time(A)
    def A(name,age):
        time.sleep(1)   #延迟一秒
        print("这是函数A")
        return '%s的年龄为%s'%(name,age)
    
    if __name__=="__main__":
        print(A('laowang','19'))   #现在的A=wrapper
    函数有参数

     还需要注意的是,在flask里面,一个装饰器可以被多个函数所使用,但是现在两个视图函数同时调用一个装饰器,就会出现一个问题

     这个错误的主要原因就是,因为装饰器返回的是内层函数wrapper的内存地址,所以当两个视图函数同时调用的时候,就相当于在flask中定义两个同样函数名的函数,所以就会出现错误

    这个错误怎么解决呢,我们只需要使用flask中一个函数(from functools import wraps)就可以了

    from flask import session,current_app,g
    from info.models import User
    from functools import wraps
    def user_login_data(func):
        """
        判断用户登陆状态
        :return: 
        """
        @wraps(func)    #解决多个视图函数同时调用的问题
        def wrapper(*args,**kwargs):
            user_id = session.get("id", None)
            # 1.2根据id在数据中查询
            user = None
            try:
                user = User.query.filter_by(id=user_id).first()
            except Exception as e:
                current_app.logger.error(e)
            g.user=user    #相当于把user存在一个盒子g里,在别的功能中和路由都可以直接访问
            return func(*args,**kwargs)    #返回函数的运行结果
        return wrapper    #返回wrapper内存地址

     

  • 相关阅读:
    【codevs1227】方格取数2(最大流费最大流-模板
    【ZJOI2008】【BZOJ1033】杀蚂蚁(占坑待填
    python基础学习1-流程控制和判断
    python基础学习1-变量定义赋值,屏幕输入输出
    Jzoj5237 最长公共子序列
    Jzoj5236 利普希茨
    [置顶] 欢迎使用CSDN-markdown编辑器
    Jzoj5235 好的排列
    Jzoj5234 外星人的路径
    Jzoj5231 序列问题
  • 原文地址:https://www.cnblogs.com/yu666666/p/13857347.html
Copyright © 2011-2022 走看看