Python 权限装饰器与日志模块:给函数穿防护马甲 + 让程序写日记
文章目录
📖 前言
第一部分:权限装饰器 —— 给函数“穿防护马甲”
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() 一条条盯着屏幕看。
两个工具让你的码农之路又获得一些技能吧,各位糕手
下期我们聊点啥呢?保持期待吧~ 咱们下期见!👋🐍
更多推荐
所有评论(0)