zoukankan      html  css  js  c++  java
  • python装饰器 语法糖

    简介:

    装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。

    比如说我们写flask,路由就是用装饰器定义的。如果写权限控制,那么权限控制一般也是由装饰器来实现的。日志记录,一般也可以通过装饰器来实现。

    简单说,就是为了给某些函数增加一种或几种功能的做法。

    下面举例实现。

    一:基本函数

    1.源码

    from time import sleep
    
    
    def watch_movie():
        print('看电影')
        sleep(3)
        print('The End')
    
    
    if __name__ == '__main__':
        watch_movie()
    View Code

    2.执行结果

    代码很简单,先打印看电影,间隔3秒,打印The End。

    二:装饰器原理

    1.目标:计算函数运行时间

    2.源码

    from time import sleep, time
    
    
    def ceal_time():
        before = time()
        watch_movie()
        after = time()
        print('函数运行%s秒' % (after - before))
    
    
    def watch_movie():
        print('看电影')
        sleep(3)
        print('The End')
    
    
    if __name__ == '__main__':
        ceal_time()
    View Code

    3.执行结果

    代码很简单,先打印看电影,间隔3秒,打印The End,然后打印函数运行计时。

    4.分析

    我们把一个函数放进另一个函数去运行,这就是装饰器的基本工作原理。

    三:改造计时函数为通用函数

    1.目标:把计算函数运行时间这个功能,适配给不同的函数。

    2.源码

    from time import sleep, time
    
    
    def ceal_time(fun):
        before = time()
        fun()
        after = time()
        print('函数运行%s秒' % (after - before))
    
    
    def watch_movie():
        print('看电影')
        sleep(3)
        print('The End')
    
    
    def play_game():
        print('玩游戏')
        sleep(3)
        print('Game Over')
    
    
    if __name__ == '__main__':
        ceal_time(watch_movie)
        ceal_time(play_game)
    View Code

    3.执行结果

    看电影和玩游戏两个函数都执行了。

    4.分析

    我们可以把函数作为对象,传入另一个函数当中。

    四:变为装饰器

    1.目标:

    我们改变了函数的调用方式,能不能不改变函数在调用位置的代码呢?

    2.源码:

    from time import sleep, time
    
    
    def ceal_time(fun):
        def wrapper():
            before = time()
            fun()
            after = time()
            print('函数运行%s秒' % (after - before))
    
        return wrapper
    
    
    @ceal_time
    def watch_movie():
        print('看电影')
        sleep(3)
        print('The End')
    
    
    # @ceal_time
    def play_game():
        print('玩游戏')
        sleep(3)
        print('Game Over')
    
    
    if __name__ == '__main__':
        watch_movie()
        play_game()
    View Code

    3.执行结果

    看电影前面加了装饰器,实现了函数运行计时,玩游戏没有加装饰器,所以没有函数运行计时。

    而且函数在main中的调用方式和没加装饰器是一样的。

    五:函数有参数

    1.目标:被装饰的函数,有参数的处理

    2.源码:

    from time import sleep, time
    
    
    def ceal_time(fun):
        def wrapper(*args, **kwargs):  # 修改
            before = time()
            fun(*args, **kwargs)  # 修改
            after = time()
            print('函数运行%s秒' % (after - before))
    
        return wrapper
    
    
    @ceal_time
    def watch_movie(name, movie):
        print('%s在看%s电影' % (name, movie))
        sleep(3)
        print('The End')
    
    
    # @ceal_time
    def play_game(name, game):
        print('%s在玩%s游戏' % (name, game))
        sleep(3)
        print('Game Over')
    
    
    if __name__ == '__main__':
        watch_movie(name='张三', movie='猫和老鼠')
        play_game(name='李四', game='魔兽争霸')
    View Code

    3.执行结果

     你可以试试看,没有了*args,**kwargs,一定是会报错的。

    六:有返回值的函数加装饰器

    1.目标:现在做的都没返回值,如何处理被装饰的函数的返回值。

    2.源码:

    from time import sleep, time
    
    
    def ceal_time(fun):
        def wrapper(*args, **kwargs):
            before = time()
            result = fun(*args, **kwargs)  # 修改
            after = time()
            print('函数运行%s秒' % (after - before))
            return result  # 返回
    
        return wrapper
    
    
    @ceal_time
    def watch_movie(name, movie):
        print('%s在看%s电影' % (name, movie))
        sleep(3)
        print('The End')
        return '电影看完了'
    
    
    # @ceal_time
    def play_game(name, game):
        print('%s在玩%s游戏' % (name, game))
        sleep(3)
        print('Game Over')
        return '游戏玩完了'
    
    
    if __name__ == '__main__':
        print(watch_movie(name='张三', movie='猫和老鼠'))
        print(play_game(name='李四', game='魔兽争霸'))
    View Code

    3.执行结果

    现在已经可以处理任何函数的装饰器操作了。

    七:权限登录

    1.目标:

    flask中未登录用户进入登录页面

    flask中登录用户进入详情页面

    2.源码一(无装饰器):

    无装饰器,简单判断session存在即可进入。

    import os
    
    from flask import Flask, request, g, redirect, url_for, session
    
    app = Flask(__name__)
    app.config['SECRET_KEY'] = os.urandom(24)
    
    
    def ceal_time(fun):
        def wrapper(*args, **kwargs):
            result = fun(*args, **kwargs)  # 修改
            return result  # 返回
    
        return wrapper
    
    
    @app.route('/')
    def index():
        return '欢迎页面'
    
    
    @app.route('/login/', methods=['GET', 'POST'])
    def login():
        if request.method == 'GET':
            html = '''
                <form action="" method="post">
                    <table>
                        <tbody>
                            <tr>
                                <td>用户名:</td>
                                <td><input type="text" name="username" placeholder="请输入用户名"></td>
                            </tr>
                            <tr>
                                <td>密码:</td>
                                <td><input type="password" name="password" placeholder="请输入密码"></td>
                            </tr>
                            <tr>
                            <td></td>
                                <td><input type="submit" value="登录"></td>
                            </tr>
                        </tbody>
                    </table>
                </form>'''
            return html
        if request.method == 'POST':
            session['sign'] = True
            return redirect(url_for('info'))
            return '登录'
    
    
    @app.route('/info/')
    def info():
        if session.get('sign'):
            return '详情页'
        else:
            return redirect(url_for('login'))
    
    
    if __name__ == '__main__':
        app.run()
    View Code

    3.源码二(有装饰器):

    import os
    
    from flask import Flask, request, g, redirect, url_for, session
    
    app = Flask(__name__)
    app.config['SECRET_KEY'] = os.urandom(24)
    
    
    def check_auth(fun):
        def wrapper(*args, **kwargs):
            if session.get('sign'):
                return fun(*args, **kwargs)  # 修改
            else:
                return redirect(url_for('login'))
    
        return wrapper
    
    
    @app.route('/')
    def index():
        return '欢迎页面'
    
    
    @app.route('/info/')
    @check_auth
    def info():
        return '详情页'
    
    
    @app.route('/login/', methods=['GET', 'POST'])
    def login():
        if request.method == 'GET':
            html = '''
                <form action="" method="post">
                    <table>
                        <tbody>
                            <tr>
                                <td>用户名:</td>
                                <td><input type="text" name="username" placeholder="请输入用户名"></td>
                            </tr>
                            <tr>
                                <td>密码:</td>
                                <td><input type="password" name="password" placeholder="请输入密码"></td>
                            </tr>
                            <tr>
                            <td></td>
                                <td><input type="submit" value="登录"></td>
                            </tr>
                        </tbody>
                    </table>
                </form>'''
            return html
        if request.method == 'POST':
            session['sign'] = True
            print(session.get('sign'))
            return redirect('/info/')
            # return redirect(url_for('info'))    #这里写url_for会出错,但是session也创建成功,直接硬跳转吧。
    
    
    if __name__ == '__main__':
        app.run()

    四:验证

    1,访问http://127.0.0.1:5000/       欢迎页面

    2,访问http://127.0.0.1:5000/login    登录页面

    3,访问http://127.0.0.1:5000/info     自动进入登录页面,

    4,登录页面点击提交,进入login的POST模式,设置session,然后自动进入详情页面。

    5,装饰器的登录验证就这样。

  • 相关阅读:
    输出函数
    curl
    页眉的章名和章名不统一
    水平柱状图
    目录和正文的页码生成
    protobuf的使用
    yarn vue安装
    nvm node的安装
    win安装postman
    机器码
  • 原文地址:https://www.cnblogs.com/jackadam/p/11877034.html
Copyright © 2011-2022 走看看