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内存地址

     

  • 相关阅读:
    Proj THUDBFuzz Paper Reading: The Art, Science, and Engineering of Fuzzing: A Survey
    Proj THUDBFuzz Paper Reading: A systematic review of fuzzing based on machine learning techniques
    9.3 付费代理的使用
    11.1 Charles 的使用
    第十一章 APP 的爬取
    10.2 Cookies 池的搭建
    10.1 模拟登录并爬取 GitHub
    11.5 Appium 爬取微信朋友圈
    11.4 Appium 的基本使用
    11.3 mitmdump 爬取 “得到” App 电子书信息
  • 原文地址:https://www.cnblogs.com/yu666666/p/13857347.html
Copyright © 2011-2022 走看看