📖 前言

在 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),DEBUGINFO 就不显示了。

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 日志级别 INFOWARNING
%(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() 一条条盯着屏幕看。

两个工具让你的码农之路又获得一些技能吧,各位糕手

下期我们聊点啥呢?保持期待吧~ 咱们下期见!👋🐍

更多推荐