文章目录
📖 前言
第一部分:权限装饰器 —— 给函数“穿防护马甲”
1.1 权限装饰器 —— 未登录有效保护
1.2 怎么调用装饰器?
1.3 @wraps(func) 是干嘛的?
1.4 装饰器核心总结
第二部分:logging 日志模块 —— 让程序学会“写日记”
2.1 为什么要用日志?
2.2 日志的五个级别(从低到高)
2.3 基础用法 —— 按你图中的代码来
2.4 图解:日志是怎么流动的
2.5 多个日志实例(独立模块)
2.6 日志格式占位符说明
2.7 日志模块核心总结
🧁 结尾
📖 前言
在 Python 编程中,我们常常会遇到一些看似简单却非常实用的技巧,它们能极大提升代码的可维护性和安全性。今天不讲复杂的概念,就聊两件特别实用的事:
第一件:权限装饰器—— 这是一种优雅的设计模式,它允许你在不改变函数本身代码的情况下,为函数“穿上防护马甲”,添加额外的功能。想象一下,你有一个需要登录才能访问的个人中心页面,传统做法是在每个函数开头都加上登录检查的代码,这样不仅重复,还容易出错。而装饰器可以让你用一行@login_required就搞定所有需要权限验证的函数,代码简洁又安全。
第二件:日志模块—— 这是程序“写日记”的能力。在开发阶段,我们习惯用print()来调试,但当程序部署到服务器上后,你不可能一直盯着屏幕看输出。日志模块让程序能够自动把运行过程中的关键信息(如错误、警告、用户操作等)记录到文件中。当程序出现问题时,你可以像查案一样翻阅日志文件,快速定位问题根源,这比靠眼睛盯着屏幕找错误靠谱一万倍。
这两件事虽然基础,但却是 Python 开发中不可或缺的实用技能。本文将按照清晰的思路,分开讲解这两个主题,每个部分都配有详细的代码示例和流程图,确保你不仅能理解原理,还能立即上手应用到自己的项目中。让我们开始吧!🚀
第一部分:权限装饰器 —— 给函数“穿防护马甲”
1.1 权限装饰器 —— 未登录有效保护
python
from functools import wraps user = None # 全局变量,记录当前登录用户,默认没人 def login_required(func): @wraps(func) # 保留原函数的名字和注释(方便调试) def check_login(): """check_login 注释说明""" global user if user: # 已经登录了 → 直接执行原函数 func() else: # 没登录 → 让用户输入账号密码 user_name = input("输入用户名:") password = input("输入密码:") if user_name == "admin" and password == "123456": user = user_name func() else: print("用户名或者密码错误") return check_login这段代码的执行逻辑:
text
调用被装饰的函数 ↓ 检查 user 是否为空 ↓ ┌────┴────┐ ↓ ↓ user 有值 user 是 None (已登录) (未登录) ↓ ↓ 直接执行 让你输账号密码 原函数 ↓ ┌───┴───┐ ↓ ↓ 正确 错误 ↓ ↓ 登录成功 提示错误 ↓ 执行原函数
1.2 怎么调用装饰器?
python
# 普通函数:不用登录就能看 def index(): print("欢迎来到首页") 加了 @login_required 的函数:必须先登录才能进 @login_required def center(): """center 是个人中心""" print("欢迎来到个人中心") @login_required def wallet(): print("欢迎来到钱包页面") 调用 index() # 直接输出:欢迎来到首页 center() # 没登录的话会让你输账号密码 wallet() # 登录过一次之后,后面的函数直接放行运行效果:
第一次调用center():
text
输入用户名:admin 输入密码:123456 欢迎来到个人中心
第二次调用wallet()(已登录,不用再输):
text
欢迎来到钱包页面
1.3@wraps(func)是干嘛的?
不加@wraps(func),你的函数名字会被“偷换”掉:
python
# 不加 @wraps def login_required(func): def check_login(): pass return check_login @login_required def center(): """我是个人中心""" pass print(center.name) # check_login ← 函数名变了!
加了@wraps(func)之后:
python
from functools import wraps def login_required(func): @wraps(func) def check_login(): pass return check_login @login_required def center(): """我是个人中心""" pass print(center.name) # center ← 还是原来的名字
📌 一句话:
@wraps的作用就是“把原函数的身份信息(名字、注释等)复制给包装函数”,方便调试和查错。
1.4 装饰器核心总结
| 概念 | 说明 |
|---|---|
| 本质 | 闭包 + 语法糖 |
| 作用 | 不改变原函数,给函数加新功能 |
@wraps | 保住原函数的名字和注释 |
global user | 在函数里修改全局变量 |
@login_required | 执行函数前先校验是否登录 |
第二部分:logging日志模块 —— 让程序学会“写日记”
2.1 为什么要用日志?
写代码的时候,你习惯用print()来调试。但程序跑在服务器上之后,你不可能一直盯着屏幕看。这时候就需要日志——程序自己把运行信息写进文件里,出问题了你去翻文件就能查到。
日志的作用:
| 场景 | 说明 |
|---|---|
| 排查错误 | 程序崩了,翻日志看哪里出了问题 |
| 监控运行 | 看程序在什么时间干了什么事 |
| 记录关键操作 | 谁在什么时候删了什么数据 |
2.2 日志的五个级别(从低到高)
| 级别 | 函数 | 啥时候用 |
|---|---|---|
| DEBUG | logger.debug() | 调试信息,最详细 |
| INFO | logger.info() | 常规运行信息 |
| WARNING | logger.warning() | 警告,不影响运行 |
| ERROR | logger.error() | 出错了,但程序还能跑 |
| CRITICAL | logger.critical() | 严重错误,程序要挂了 |
📌级别规则:设置了
setLevel(logging.WARNING),就只会记录WARNING及以上级别(WARNING、ERROR、CRITICAL),DEBUG和INFO就不显示了。
2.3 基础用法 —— 按你图中的代码来
python
import logging 1. 创建日志实例 logger = logging.getLogger(name) # name 是当前模块名 logger.setLevel(logging.DEBUG) # 设置级别,覆盖默认的 WARNING 2. 创建控制台处理器(输出到屏幕) stream_handler = logging.StreamHandler() stream_handler.setLevel(logging.INFO) # 控制台只显示 INFO 及以上 设置控制台输出格式 stream_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') stream_handler.setFormatter(stream_formatter) 把处理器添加到日志实例 logger.addHandler(stream_handler) 3. 创建文件处理器(输出到文件) file_handler = logging.FileHandler('log.txt') file_handler.setLevel(logging.WARNING) # 文件只记录 WARNING 及以上 设置文件输出格式 file_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') file_handler.setFormatter(file_formatter) 把处理器添加到日志实例 logger.addHandler(file_handler) 4. 输出日志 logger.debug("debug 信息") # 只有控制台显示(因为控制台是 INFO,会显示 DEBUG 及以上) logger.info("info 信息") # 控制台显示(INFO 及以上),文件不显示(WARNING 以下不记录) logger.warning("warning 信息") # 控制台 + 文件都显示 logger.error("error 信息") # 控制台 + 文件都显示 logger.critical("critical 信息")# 控制台 + 文件都显示2.4 图解:日志是怎么流动的
text
logger.setLevel(DEBUG) ↓ 日志实例(总开关:DEBUG) ↓ ┌────┴────┐ ↓ ↓ 控制台处理器 文件处理器 setLevel(INFO) setLevel(WARNING) ↓ ↓ 显示 INFO及以上 显示 WARNING及以上 ↓ ↓ 屏幕 log.txt
📌一句话:总开关决定哪些日志能进系统,各个处理器再根据自己的级别决定哪些显示到屏幕、哪些写到文件。
2.5 多个日志实例(独立模块)
不同模块可以用各自的日志实例,互不干扰:
python
# 在另一个文件或另一个模块里 logger2 = logging.getLogger("用户模块") logger2.setLevel(logging.DEBUG) file_handler = logging.FileHandler('log2.txt', encoding='utf-8') file_handler.setLevel(logging.WARNING) file_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') file_handler.setFormatter(file_formatter) logger2.addHandler(file_handler) logger2.info("用户登录了") # 只显示在屏幕 logger2.warning("用户多次输错密码") # 显示在屏幕 + 写入 log2.txt💡
logging.getLogger("用户模块")里的名字会出现在日志中,方便你区分是哪块代码打的日志。
2.6 日志格式占位符说明
| 占位符 | 含义 | 示例 |
|---|---|---|
%(asctime)s | 时间 | 2026-07-30 14:30:25 |
%(name)s | 日志实例名称 | __main__或用户模块 |
%(levelname)s | 日志级别 | INFO、WARNING |
%(message)s | 日志内容 | 你写的具体信息 |
%(filename)s | 文件名 | demo.py |
%(lineno)d | 行号 | 10 |
2.7 日志模块核心总结
| 组件 | 作用 |
|---|---|
getLogger(name) | 创建日志实例 |
setLevel() | 设置总级别 |
StreamHandler() | 输出到控制台(屏幕) |
FileHandler() | 输出到文件 |
Formatter() | 设置日志格式 |
logger.debug/info/warning/error/critical() | 输出不同级别的日志 |
🎯 今天知识点速查
装饰器部分
| 概念 | 说明 |
|---|---|
@login_required | 加登录校验装饰器 |
@wraps(func) | 保住原函数名字 |
global user | 修改全局变量 |
| 本质 | 闭包 + 语法糖 |
日志部分
| 级别 | 函数 | 用途 |
|---|---|---|
| DEBUG | logger.debug() | 调试信息 |
| INFO | logger.info() | 常规信息 |
| WARNING | logger.warning() | 警告 |
| ERROR | logger.error() | 错误 |
| CRITICAL | logger.critical() | 严重错误 |
🧁 结尾
今天两件事都不难,但特别实用:
权限装饰器能为你的网页在未登录时提供有效保护,避免非法访问和攻击。
日志模块让你程序学会写日记,出了错翻文件查,不用靠print()一条条盯着屏幕看。
两个工具让你的码农之路又获得一些技能吧,各位糕手
下期我们聊点啥呢?保持期待吧~ 咱们下期见!👋🐍