python装饰器 语法糖
简介:#
装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。
比如说我们写flask,路由就是用装饰器定义的。如果写权限控制,那么权限控制一般也是由装饰器来实现的。日志记录,一般也可以通过装饰器来实现。
简单说,就是为了给某些函数增加一种或几种功能的做法。
下面举例实现。
一:基本函数#
1.源码#

from time import sleep def watch_movie(): print('看电影') sleep(3) print('The End') if __name__ == '__main__': watch_movie()
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()
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)
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()
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='魔兽争霸')
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='魔兽争霸'))
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()
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,装饰器的登录验证就这样。
作者:上官飞鸿
出处:https://www.cnblogs.com/jackadam/p/11877034.html
版权:本作品采用「知识共享-署名-非商业性-禁止演绎(CC-BY-NC-ND)」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!