Python 模块与包
本章学习知识点
- 模块导入:import 模块、from 模块 import 函数、自定义模块
- 常用标准库:
- os/sys:系统操作(文件路径、环境变量)
- datetime:时间处理(日期转换、计时)
- json:JSON 数据解析与生成
- collections:高级数据结构(defaultdict、deque、Counter)
模块与包是 Python 代码模块化、可维护性的核心,能让你实现「代码复用、功能拆分、第三方集成」。本手册聚焦 模块导入机制、自定义模块与包 ,并深入讲解高频实用的标准库(os/sys/datetime/json/collections)
一、模块与包基础
1.1 核心概念
-
模块(Module) :一个
.py文件就是一个模块,包含变量、函数、类等代码,可被其他文件导入使用(核心价值:代码复用)。 -
包(Package):包含:
__init__.py文件的文件夹,用于组织多个相关模块(核心价值:按功能拆分代码,避免模块名冲突)。- 注意:Python 3.3+ 支持「命名空间包」(无需
__init__.py),但推荐保留__init__.py用于初始化包、控制导入行为。
- 注意:Python 3.3+ 支持「命名空间包」(无需
1.2 模块导入机制
-
Python 导入模块时,会按以下顺序查找模块文件:
- 当前执行脚本所在目录(优先);
- 系统环境变量
PYTHONPATH指定的目录; - Python 安装目录下的标准库目录;
- 第三方库目录(如
site-packages)。
-
导入模块的 4 种常用方式,需根据场景灵活选择:
-
import 模块名(导入整个模块)-
语法:
import 模块名 [as 别名] -
特点:导入整个模块,通过「模块名。属性」访问模块内的函数 / 变量 / 类,避免命名冲突。
-
适用场景:模块功能较多,需多次使用模块内的不同属性。
python# 示例1:导入标准库模块(无别名) import math print(math.pi) # 访问模块变量 → 3.141592653589793 print(math.sqrt(16)) # 调用模块函数 → 4.0 计算平方根比如25返回就是5 # 示例2:导入模块并指定别名(简化书写) import datetime as dt current_time = dt.datetime.now() print(current_time) # 输出当前时间 → 2025-11-27 10:00:00.123456
-
-
from 模块名 import 属性(导入模块指定属性)-
语法:
from 模块名 import 函数/变量/类 [as 别名] -
特点:直接导入模块内的指定属性,可直接使用(无需加模块名前缀),代码更简洁。
-
适用场景:仅需使用模块内的少数几个属性。
python# 示例1:导入模块的单个属性 from math import pi, sqrt print(pi) # 直接使用变量 → 3.141592653589793 print(sqrt(25)) # 直接调用函数 → 5.0 # 示例2:导入属性并指定别名(避免命名冲突) from math import pow as power print(power(2, 3)) # 调用别名函数 → 8.0 # 示例3:导入模块的所有属性(不推荐,易冲突) from math import * print(sin(pi/2)) # 直接使用所有属性 → 1.0 # 警告:若当前文件有同名函数/变量,会被覆盖
-
-
from 包名 import 模块(导入包内模块)-
语法:
from 包名 import 模块名 [as 别名]或from 包名.模块名 import 属性 -
特点:按包的层级结构导入模块,适合大型项目的代码组织。
python# 假设项目结构如下: # my_project/ # main.py # utils/ # 包 # __init__.py # file_ops.py # 模块(含 read_file 函数) # str_ops.py # 模块(含 format_str 函数) # 在 main.py 中导入包内模块 from utils import file_ops content = file_ops.read_file("test.txt") # 包.模块.函数 # 直接导入包内模块的属性 from utils.str_ops import format_str formatted = format_str("hello") # 直接使用函数 # 导入包内模块并指定别名 from utils import file_ops as fo content = fo.read_file("test.txt")
-
-
import 包名.模块名(完整路径导入)-
语法:
import 包名.模块名 [as 别名] -
特点:明确指定模块的完整路径,可读性强,避免同名模块冲突。
python# 延续上面的项目结构 import utils.file_ops content = utils.file_ops.read_file("test.txt") # 完整路径导入并指定别名 import utils.str_ops as so formatted = so.format_str("hello")
-
-
1.3 自定义模块
自定义模块就是创建 .py 文件,编写代码后供其他文件导入,步骤如下:
-
创建模块文件(
my_module.py)python# my_module.py(自定义模块) # 模块变量 MODULE_NAME = "我的自定义模块" VERSION = "1.0" # 模块函数 def add(a, b): """两数相加""" return a + b def multiply(a, b): """两数相乘""" return a * b # 模块类 class Calculator: def subtract(self, a, b): """两数相减""" return a - b -
导入自定义模块(在同一目录下的
main.py)python# main.py # 方式1:导入整个模块 import my_module print(my_module.MODULE_NAME) # 访问变量 → 我的自定义模块 print(my_module.add(3, 5)) # 调用函数 → 8 calc = my_module.Calculator() print(calc.subtract(10, 4)) # 调用类方法 → 6 # 方式2:导入模块指定属性 from my_module import multiply, Calculator print(multiply(4, 5)) # → 20 calc2 = Calculator() print(calc2.subtract(20, 7)) # → 13 # 方式3:导入模块并指定别名 import my_module as mm print(mm.VERSION) # → 1.0 -
注意事项:
-
模块名遵循 PEP8 规范(小写 + 下划线,如
my_module),避免与标准库 / 第三方库模块名冲突(如不要命名为os.py、json.py); -
若自定义模块不在当前目录,需将模块所在目录添加到
sys.path(见下文sys库); -
模块被导入时,其顶层代码(如变量定义、函数定义、类定义)会被执行一次(可通过
if __name__ == "__main__":控制仅在直接运行模块时执行的代码)。python# 优化 my_module.py:添加主程序入口 if __name__ == "__main__": # 仅当直接运行 my_module.py 时执行(导入时不执行) print("直接运行自定义模块") print(add(2, 3)) # 测试函数
-
1.4 自定义包
自定义包用于组织多个相关模块,步骤如下:
-
创建包结构
python# 项目结构 my_project/ main.py tools/ # 包名 __init__.py # 包初始化文件(可空,也可用于导入配置) math_ops.py # 模块1:数学运算 str_ops.py # 模块2:字符串处理 -
编写包内模块代码
python# tools/math_ops.py def calculate_sum(n): """计算1到n的和""" return sum(range(1, n+1)) # tools/str_ops.py def reverse_str(s): """反转字符串""" return s[::-1] -
(可选)优化
__init__.py(控制包导入行为)-
__init__.py可用于:1. 初始化包变量;2. 简化导入路径(通过__all__指定默认导入的模块 / 属性)。python# tools/__init__.py # 包变量 PACKAGE_DESCRIPTION = "工具包:包含数学运算和字符串处理功能" # 指定 from tools import * 时导入的模块(可选) __all__ = ["math_ops", "str_ops"] # 简化导入:让用户可直接 from tools import calculate_sum from .math_ops import calculate_sum from .str_ops import reverse_str
-
-
导入包并使用
python# main.py # 方式1:导入包内模块 from tools import math_ops, str_ops print(math_ops.calculate_sum(10)) # → 55 print(str_ops.reverse_str("hello")) # → olleh # 方式2:通过 __init__.py 简化导入(直接导入属性) from tools import calculate_sum, reverse_str print(calculate_sum(5)) # → 15 print(reverse_str("python")) # → nohtyp # 方式3:导入整个包 import tools print(tools.PACKAGE_DESCRIPTION) # 访问包变量 print(tools.calculate_sum(8)) # 调用简化导入的函数
二、常用标准库实战
Python 标准库是内置的「工具集」,无需安装即可使用,以下是开发中最常用的 5 个标准库,覆盖系统操作、时间处理、数据解析、高级数据结构等核心场景。
| 模块大类 | 子模块 / 核心功能 | 核心用途 | 关键特性 / 适用场景 |
|---|---|---|---|
| 时间处理模块 | datetime | 时间运算(增减)、时间字段修改、高精度时间获取 | 比 time 更直观,支持 timedelta 时间差计算 |
| 文件与目录操作模块 | os | 目录增删、路径处理、系统环境获取、文件属性查看 | 跨系统路径兼容,基础文件 / 目录管理 |
| 系统交互模块 | sys | 获取 Python 解释器信息、命令行参数处理、程序退出控制 | 命令行工具开发、系统参数获取 |
| 数据序列化模块 | json | 跨语言数据序列化 / 反序列化,支持基础数据类型 | 多语言交互、接口数据传输 |
| 数据结构扩展模块 | collections | 提供高性能专用数据结构(Counter、defaultdict、OrderedDict、deque 等) | 弥补内置数据结构不足,提升开发效率 |
2.1、sys 库
sys 库用于与 Python 解释器本身交互,核心功能包括「命令行参数获取、系统路径配置、退出程序」等。
-
核心功能与方法
方法 / 属性 功能描述 示例 sys.argv获取命令行参数(列表,第一个元素是脚本名) 运行 python main.py 10 20→sys.argv → ["main.py", "10", "20"]sys.pathPython 模块搜索路径列表(可动态添加) print(sys.path) → [当前目录, 标准库目录, ...]sys.version获取 Python 版本信息 print(sys.version) → 3.9.7 (default, ...)sys.platform获取操作系统平台 print(sys.platform) → linux/win32/darwin(Mac)sys.exit(code=0)退出程序(code=0 表示正常退出,非 0 表示异常) sys.exit(1)(异常退出)sys.stdin标准输入流(如读取用户输入) line = sys.stdin.readline()sys.stdout标准输出流(如打印内容) sys.stdout.write("Hello") -
示例
pythonimport sys # 1. 解析命令行参数(实现简易计算器) print("命令行参数:", sys.argv) if len(sys.argv) != 4: print("用法:python main.py <操作符> <数字1> <数字2>") print("示例:python main.py add 10 20") sys.exit(1) # 异常退出(非 0 状态码) op = sys.argv[1] num1 = float(sys.argv[2]) num2 = float(sys.argv[3]) if op == "add": print(f"{num1} + {num2} = {num1 + num2}") elif op == "sub": print(f"{num1} - {num2} = {num1 - num2}") elif op == "mul": print(f"{num1} × {num2} = {num1 * num2}") elif op == "div": if num2 == 0: print("错误:除数不能为 0") sys.exit(1) print(f"{num1} ÷ {num2} = {num1 / num2:.2f}") else: print("支持的操作符:add/sub/mul/div") sys.exit(1) ############ 写法2 ############ import sys print(sys.argv) if len(sys.argv) != 4 or len(sys.argv) >= 5: print("用法:python main.py <操作符[add,sub,mul]> <数字1> <数字2>") print("示例:python main.py add 10 20") sys.exit(1) # 异常退出(非 0 状态码) # 如果不去掉第1个 控制台四个参数 打印['绝对路径/名称.py', 'add', '10', '20'] operator = sys.argv[1::] def args(*args): num1=float(args[1]) num2=float(args[2]) if args[0]=='add': print(num1+num2) elif args[0]=='sub': print(num1-num2) elif args[0]=='mul': print(num1*num2) else: print("请输入正确的操作符") sys.exit(1) args(*operator) # 2. 动态添加模块搜索路径(导入非当前目录的自定义模块) # 假设自定义模块在 /home/user/my_modules 目录下 custom_module_dir = "/home/user/my_modules" if custom_module_dir not in sys.path: sys.path.append(custom_module_dir) # 添加到搜索路径 print(f"已添加模块路径:{custom_module_dir}") # 之后即可导入该目录下的模块 # import my_custom_module
2.1、os 库
os 库提供与操作系统交互的接口,核心用于「文件路径操作、目录管理、系统命令执行」,是文件处理的基础。
-
核心功能与方法
方法 / 属性 功能描述 示例 os.getcwd()获取当前工作目录 print(os.getcwd()) → /home/user/projectos.chdir(path)切换工作目录 os.chdir("/home/user")os.listdir(path=".")列出目录下的所有文件 / 子目录 os.listdir("./tools") → ["math_ops.py", ...]os.mkdir(path)创建单个目录(父目录必须存在) os.mkdir("./data")os.makedirs(path)递归创建目录(父目录不存在则自动创建) os.makedirs("./data/logs")os.remove(path)删除文件 os.remove("./test.txt")os.rmdir(path)删除空目录 os.rmdir("./data")os.removedirs(path)递归删除空目录 os.removedirs("./data/logs")os.rename(old, new)重命名文件 / 目录 os.rename("old.txt", "new.txt")os.path.exists(path)判断路径是否存在(文件 / 目录) os.path.exists("./tools") → Trueos.path.isfile(path)判断是否为文件 os.path.isfile("./main.py") → Trueos.path.isdir(path)判断是否为目录 os.path.isdir("./tools") → Trueos.path.join(p1, p2, ...)拼接路径(自动适配系统分隔符) os.path.join("./data", "logs") → ./data/logsos.path.abspath(path)获取路径的绝对路径 os.path.abspath("./main.py") → /home/user/project/main.pyos.path.splitext(path)分割文件名和扩展名 os.path.splitext("test.txt") → ("test", ".txt") -
示例
pythonimport os # 1. 路径拼接(跨平台兼容) # 错误方式:直接用 + 拼接(Windows 用 \,Linux 用 /,易出错) # bad_path = "./data" + "/logs" # 正确方式:用 os.path.join data_dir = os.path.join(os.getcwd(), "data") log_dir = os.path.join(data_dir, "logs") print("日志目录路径:", log_dir) # 2. 目录创建(不存在则创建) if not os.path.exists(log_dir): os.makedirs(log_dir) # 递归创建 print(f"目录 {log_dir} 创建成功") else: print(f"目录 {log_dir} 已存在") # 3. 遍历目录下的所有 .py 文件 project_dir = os.getcwd() py_files = [] for root, dirs, files in os.walk(project_dir): # 递归遍历目录 for file in files: if file.endswith(".py"): # 筛选 .py 文件 file_path = os.path.join(root, file) py_files.append(file_path) print(f"\n项目中所有 .py 文件(共 {len(py_files)} 个):") for path in py_files: print(path) # 4. 文件重命名(批量修改后缀) current_path=os.path.dirname(os.path.abspath(__file__)) file_list=["file1.txt","file2.txt","file3.txt"] for file in file_list: get_check_file_path=os.path.join(current_path,"bac") # 多用os.getpwd()看一下当前路径 name,type=os.path.splitext(file) # "filex",".txt" newe_nam=name+".md" # 改为 .md 后缀 os.rename(os.path.join(get_check_file_path,file), os.path.join(get_check_file_path,newe_nam)) print(f"旧文件:{file} --> 新文件:{os.path.join(get_check_file_path,newe_nam)}") -
获取「脚本文件所在目录」
python# 当前在【D:\docker\miscellaneous\python\模块与包\模块使用】下使用os.getcwd(),查看只到 D:\docker\miscellaneous\python 怎么获取到 D:\docker\miscellaneous\python\模块与包\模块使用 # # 获取当前脚本文件的绝对路径 script_path = os.path.abspath(__file__) # 获取脚本文件所在的目录(即模块使用目录) script_dir = os.path.dirname(script_path) os.chdir(os.path.dirname(os.path.abspath(__file__))) print(os.getcwd())
2.3、datetime 库
datetime 库是 Python 处理时间的核心库,支持「日期转换、时间计算、格式化输出」,比 time 库更强大、易用。
-
核心功能与方法
类 / 方法 功能描述 示例 datetime.datetime.now()获取当前本地时间(datetime 对象) dt.now() → 2025-11-27 10:30:00.123456datetime.date.today()获取当前日期(date 对象) date.today() → 2025-11-27datetime.datetime.strptime(date_str, format)字符串转 datetime 对象 strptime("2025-11-27", "%Y-%m-%d") → 2025-11-27 00:00:00datetime.datetime.strftime(format)datetime 对象转字符串 dt.strftime("%Y-%m-%d %H:%M:%S") → "2025-11-27 10:30:00"datetime.timedelta(days/hours/minutes/seconds)时间间隔对象(用于时间计算) timedelta(days=1) → 1 天dt1 - dt2两个 datetime 对象相减,返回 timedelta dt.now() - dt(2025,1,1) → 330 天...dt + timedeltadatetime 对象加时间间隔,返回新 datetime dt.now() + timedelta(hours=3) → 3 小时后timestamp 将时间转换为时间戳 fromtimestamp 将时间戳转换为时间 时间格式化符号(常用):
%Y:4 位年份(如 2025)%m:2 位月份(01-12)%d:2 位日期(01-31)%H:24 小时制(00-23)%M:分钟(00-59)%S:秒(00-59)%w:星期(0-6,0 是周日)
-
示例
pythonfrom datetime import datetime, date, timedelta # 1. 获取当前时间与日期 current_dt = datetime.now() # 含时分秒毫秒 current_date = date.today() # 仅日期 print("当前完整时间:", current_dt) print("当前日期:", current_date) print("当前小时:", current_dt.hour) print("当前星期:", current_dt.weekday()) # 0=周一,6=周日 # 2. 时间格式化(datetime → 字符串) formatted_dt = current_dt.strftime("%Y-%m-%d %H:%M:%S") print("格式化时间:", formatted_dt) # → 2025-11-27 10:35:22 # 3. 字符串转时间(字符串 → datetime) time_str = "2025-12-01 12:00:00" parsed_dt = datetime.strptime(time_str, "%Y-%m-%d %H:%M:%S") print("解析后的时间:", parsed_dt) print("解析后的年份:", parsed_dt.year) # 4. 时间计算(加减时间间隔) # 3天后的时间 three_days_later = current_dt + timedelta(days=3) print("3天后:", three_days_later.strftime("%Y-%m-%d")) # 2小时30分钟前的时间 two_hours_ago = current_dt - timedelta(hours=2, minutes=30) print("2小时30分钟前:", two_hours_ago.strftime("%H:%M:%S")) # 计算两个日期的差值 date1 = date(2025, 1, 1) date2 = date(2025, 11, 27) delta = date2 - date1 print("两个日期相差:", delta.days, "天") # 5. 函数执行计时(统计代码运行时间) def test_func(): sum(range(1, 1000000)) start_time = datetime.now() test_func() end_time = datetime.now() duration = (end_time - start_time).total_seconds() # 耗时(秒) print(f"函数执行耗时:{duration:.4f} 秒") # 时间戳转换 print(dt.datetime.now().timestamp()) # 1764573102.217211 print(dt.datetime.fromtimestamp(1764573102.217211))
2.4、json 库
JSON 是前后端交互、数据存储的常用格式,json 库支持「JSON 字符串 → Python 对象」(解析)和「Python 对象 → JSON 字符串」(生成)。
-
核心映射关系(Python ↔ JSON)
Python 类型 JSON 类型 dict object(对象) list/tuple array(数组) str string(字符串) int/float number(数字) True true False false None null -
核心方法
功能描述 方法 示例 Python 对象 → JSON 字符串(indent 格式化输出) json.dumps(obj, ensure_ascii=False, indent=2)dumps({"name":"小明"}, ensure_ascii=False) → '{"name":"小明"}'JSON 字符串 → Python 对象 json.loads(json_str)loads('{"name":"小明"}') → {"name":"小明"}Python 对象 → JSON 文件(fp 是文件对象) json.dump(obj, fp, ensure_ascii=False, indent=2)dump(data, open("data.json", "w"))JSON 文件 → Python 对象 json.load(fp)load(open("data.json", "r")) → data -
实战
pythonimport json # 1. Python 对象 → JSON 字符串(生成) data = { "name": "小明", "age": 20, "gender": "男", "is_student": True, "hobbies": ["篮球", "音乐", "旅行"], "address": { "city": "上海", "district": "浦东新区" }, "score": None } # dumps 生成 JSON 字符串(ensure_ascii=False 保留中文,indent=2 格式化) json_str = json.dumps(data, ensure_ascii=False, indent=2) print("JSON 字符串:") print(json_str) # 2. JSON 字符串 → Python 对象(解析) parsed_data = json.loads(json_str) print("\n解析后的 Python 对象:") print(type(parsed_data)) # → <class 'dict'> print("姓名:", parsed_data["name"]) print("爱好:", parsed_data["hobbies"][0]) # 3. Python 对象 → JSON 文件(写入文件) current_dir= os.path.dirname(os.path.abspath(__file__)) with open(f"{os.path.join(current_dir, 'data.json')}", 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) print(f"数据已保存到 {current_dir}") # 4. JSON 文件 → Python 对象(读取文件) with open(f"{os.path.join(current_dir, 'data.json')}", 'r', encoding='utf-8') as f: loaded_data = json.load(f) print("\n从文件读取的 JSON 数据:") print(loaded_data["address"]["city"]) # → 上海 # 5. 处理复杂 JSON 数据(嵌套解析) complex_json = ''' { "code": 200, "message": "success", "data": { "total": 2, "users": [ {"id": 1, "name": "小红", "age": 18}, {"id": 2, "name": "小李", "age": 19} ] } } ''' result = json.loads(complex_json) if result["code"] == 200: users = result["data"]["users"] print("\n用户列表:") for user in users: print(f"ID:{user['id']},姓名:{user['name']}")
2.5、collections
collections 库提供了比内置数据结构(list/dict/set/tuple)更强大的扩展类型,解决了内置结构的诸多痛点(如字典缺省值、有序字典、计数统计等)。
-
核心类型与用法
-
defaultdict:带默认值的字典-
痛点:内置
dict访问不存在的键会报错,需用get(key, default)或判断键是否存在; -
解决方案:
defaultdict初始化时指定「默认值类型 / 函数」,访问不存在的键时自动生成默认值。pythonfrom collections import defaultdict # 示例1:默认值为列表(用于分组) student_scores = [ ("小明", "数学", 90), ("小明", "英语", 85), ("小红", "数学", 95), ("小红", "英语", 88) ] # defaultdict(list):不存在的键默认生成空列表 score_dict = defaultdict(list) for name, subject, score in student_scores: score_dict[name].append((subject, score)) # 无需判断 name 是否存在 print("学生成绩分组:") for name, scores in score_dict.items(): print(f"{name}:{scores}") # 输出: # 小明:[('数学', 90), ('英语', 85)] # 小红:[('数学', 95), ('英语', 88)] # 示例2:默认值为整数(用于计数) word_count = defaultdict(int) words = ["apple", "banana", "apple", "cherry", "banana", "apple"] for word in words: # defaultdict(<class 'int'>, {'apple': 3, 'banana': 2, 'cherry': 1}) word_count[word] += 1 # 不存在的键默认值为 0,直接累加 print("\n单词计数:", dict(word_count)) # → {'apple':3, 'banana':2, 'cherry':1}
-
-
-
Counter:计数统计工具-
功能:专门用于「可迭代对象的元素计数」,比
defaultdict(int)更简洁、功能更强。pythonfrom collections import Counter # 示例1:字符串字符计数 s = "abracadabra" char_count = Counter(s) print("字符计数:", char_count) # → Counter({'a':5, 'b':2, 'r':2, 'c':1, 'd':1}) # 示例2:列表元素计数 nums = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4] num_count = Counter(nums) print("数字计数:", num_count) # → Counter({4:4, 3:3, 2:2, 1:1}) # 示例3:获取Top N元素(常用场景) top2 = num_count.most_common(2) # 获取出现次数最多的2个元素 print("出现次数最多的2个数字:", top2) # → [(4,4), (3,3)] # 示例4:计数器运算(交集/并集/差集) c1 = Counter([1,2,3,3]) c2 = Counter([3,4,4,5]) print("交集(共同元素的最小计数):", c1 & c2) # → Counter({3:1}) print("并集(所有元素的最大计数):", c1 | c2) # → Counter({1:1,2:1,3:2,4:2,5:1}) print("差集(c1有但c2没有的元素):", c1 - c2) # → Counter({1:1,2:1,3:1})
-
-
deque:双端队列(高效增删)-
痛点:内置
list是动态数组,头部增删元素(insert(0)/pop(0))效率低(时间复杂度 O (n)); -
解决方案:
deque是双端队列,头部 / 尾部增删元素效率极高(时间复杂度 O (1)),支持最大长度限制。pythonfrom collections import deque # 示例1:基础操作(头部/尾部增删) dq = deque([1, 2, 3]) dq.append(4) # 尾部添加 → deque([1,2,3,4]) dq.appendleft(0) # 头部添加 → deque([0,1,2,3,4]) dq.pop() # 尾部删除 → 4 → deque([0,1,2,3]) dq.popleft() # 头部删除 → 0 → deque([1,2,3]) print("双端队列:", dq) # 示例2:最大长度限制(超出则自动删除另一端元素) limited_dq = deque(maxlen=3) # 最大长度3 limited_dq.append(1) limited_dq.append(2) limited_dq.append(3) print("限制长度3的队列:", limited_dq) # → deque([1,2,3], maxlen=3) limited_dq.append(4) # 超出长度,删除头部元素1 print("添加4后:", limited_dq) # → deque([2,3,4], maxlen=3) # 示例3:高效滑动窗口(常用场景) def sliding_window(nums, k): dq = deque() result = [] for i, num in enumerate(nums): # 移除窗口外的元素(索引小于 i-k+1 的元素) while dq and dq[0] < i - k + 1: dq.popleft() # 移除队列中比当前元素小的元素(维护队列递减) while dq and nums[dq[-1]] < num: dq.pop() dq.append(i) # 窗口大小达到 k 后,记录最大值(队列头部) if i >= k - 1: result.append(nums[dq[0]]) return result nums = [1, 3, -1, -3, 5, 3, 6, 7] k = 3 print("滑动窗口最大值:", sliding_window(nums, k)) # → [3,3,5,5,6,7]
-
三、综合实战
-
日志收集工具(os+datetime+json+collections)
python""" 功能:收集指定目录下的日志文件,解析错误日志,统计错误类型并保存为 JSON 报告 技术点:os 目录遍历、datetime 时间处理、json 数据生成、collections.Counter 计数 """ import os import json from datetime import datetime from collections import Counter def collect_error_logs(log_dir, output_file): # 1. 验证日志目录是否存在 if not os.path.isdir(log_dir): print(f"错误:目录 {log_dir} 不存在") return # 2. 遍历目录下的所有 .log 文件 error_records = [] error_types = [] for root, dirs, files in os.walk(log_dir): for file in files: if file.endswith(".log"): log_file_path = os.path.join(root, file) print(f"正在解析日志文件:{log_file_path}") # 3. 读取日志文件,筛选错误日志(假设错误日志以 ERROR: 开头) with open(log_file_path, "r", encoding="utf-8", errors="ignore") as f: for line_num, line in enumerate(f, start=1): line = line.strip() if line.startswith("ERROR:"): # 解析日志时间(假设日志格式:[2025-11-27 10:00:00] ERROR: ...) if "[" in line and "]" in line: time_str = line.split("]")[0].strip("[") try: log_time = datetime.strptime(time_str, "%Y-%m-%d %H:%M:%S") except ValueError: log_time = None else: log_time = None # 记录错误详情 error_info = { "file": log_file_path, "line": line_num, "time": log_time.strftime("%Y-%m-%d %H:%M:%S") if log_time else "未知", "message": line } error_records.append(error_info) # 提取错误类型(假设错误格式:ERROR: 类型: 描述) if ": " in line[6:]: # 跳过 "ERROR:" 前缀 error_type = line[6:].split(": ")[0].strip() error_types.append(error_type) # 4. 统计错误类型 error_count = Counter(error_types) if error_types else {} # 5. 生成报告数据 report = { "report_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "log_dir": log_dir, "total_error_count": len(error_records), "error_type_statistics": dict(error_count), "error_details": error_records } # 6. 保存报告为 JSON 文件 with open(output_file, "w", encoding="utf-8") as f: json.dump(report, f, ensure_ascii=False, indent=2) print(f"\n日志收集完成!共发现 {len(error_records)} 条错误,报告已保存至:{output_file}") # 执行日志收集 if __name__ == "__main__": # 日志目录(可替换为实际目录) target_log_dir = "./logs" # 输出报告文件 output_json = "error_report.json" # 执行收集 collect_error_logs(target_log_dir, output_json)
四、易错点总结
- 模块命名冲突:自定义模块名与标准库(如
os.py、json.py)或第三方库同名,导致导入错误(解决方案:修改自定义模块名); - 路径拼接错误:直接用
+拼接路径(如"./data" + "/logs"),不兼容 Windows/Linux 系统(解决方案:用os.path.join); - JSON 中文乱码:
json.dump时未指定ensure_ascii=False,导致中文被转义为 Unicode 编码(解决方案:添加ensure_ascii=False); datetime格式化错误:混用格式化符号(如%Y写成%y,%H写成%h),导致解析 / 格式化失败(解决方案:熟记常用格式化符号);deque与list混淆:用list进行头部高频增删操作,导致效率低下(解决方案:改用collections.deque);- 模块导入路径问题:自定义模块不在当前目录,且未添加到
sys.path,导致导入失败(解决方案:sys.path.append(模块目录)); defaultdict默认值类型错误:初始化时指定错误的默认值类型(如需要列表却指定int),导致后续操作报错(解决方案:根据场景选择默认值类型)。