第五课：把日志统计写成可复用的函数

先解压，再用 VS Code 打开整个文件夹。每个独立短例分别运行，不要把所有代码追加到同一个文件。
本课只使用 Python 自带的功能，不需要安装额外的软件包。
Windows 终端可用 python；macOS 终端通常用 python3。选择课堂已配置好的 Python 解释器即可。

一、跟着网页运行短例
演示/01_first_call.py：函数定义、调用和返回。
演示/02_parameters.py：默认参数、位置参数、关键字参数和耗时边界。
演示/03_return_print.py：显示结果与返回结果的区别。
演示/04_local_scope.py：局部变量和两次独立调用。
演示/04_object_arguments.py：修改传入字典与给局部名称重新赋值的区别。
演示/04_mutable_defaults.py：有意对比共享默认列表与每次新建列表。
演示/05_count_field.py：用同一个函数统计不同字段。
演示/07_top_k.py：使用 Counter 取得出现次数最多的前 K 项。
演示/08_return_position.py：比较 return 在循环内和循环后的位置。
演示/08_return_paths.py：输入无效时提前返回，其他输入返回判断结果。
演示/08_split_results.py：一次返回一个元组，再接住两个分类列表。

二、完成三个文件的组合
打开演示/06_modules 文件夹，确认 records.py、log_tools.py、main.py 都在同一文件夹，再运行 main.py。
这里先完成筛选、级别统计和耗时统计，尚不使用 Counter。
observe_import.py 是导入与调用的观察短例：先导入 main，再明确调用 main.main()。
import_forms.py 对比导入模块、导入函数和给模块起别名；三个调用都得到 True。
function_name.py 先把函数交给 rule，再使用 rule(1000) 调用它。
read_help.py 用 help(is_valid) 阅读函数名称、参数和说明。
直接运行 main.py 会显示统计；只导入 main 不会自行显示统计。

三、运行完整演示
演示/09_final_project 中的三个文件加入了来源 IP 的 Top-3 排名。运行其中的 main.py。
演示/09_final_single.py 把同一个程序放在一个文件中；两种组织方式的输出相同。
请不要把 log_tools.py 改名为 collections.py，以免与 Python 自带模块重名。

四、完成自己的统计任务
进入学生练习文件夹。records.py 和 log_tools.py 已提供。
先在 function_task.py 中设计并写出 select_valid(records)，返回有效记录的新列表，保持原顺序且不修改原记录。
按文件中的提示，用八条课堂日志、空列表、全无效输入和重复调用观察函数的结果。
然后在 main.py 的开头添加 from function_task import select_valid，再完成六个调用步骤。
先运行这两个练习文件时，只会显示数据与任务提示。写好自己的处理步骤后，再显示实际统计结果。
运行时应使用学生练习文件夹中的 main.py。
练习目标：复用已有函数统计设备、事件、事件 Top-2，以及耗时达到 1500 毫秒的记录。
先用课堂日志运行，再尝试空列表和全无效记录，解释统计结果的变化。

五、理解本课数据
这些记录为课堂模拟日志，来源 IP 使用文档示例地址，不对应本课中访问的真实网络设备。
每条记录都已有完整字段：timestamp、log_level、source_ip、device、event、duration_ms。
log_level 必须为 INFO、WARN 或 ERROR，duration_ms 必须不小于 0，才计为有效记录。
后续统计只使用有效记录。INFO、WARN、ERROR 是原始级别，与第四课的处理类别分别理解。
达到耗时阈值的 ERROR 记录也要计入耗时统计。
次数并列时保留首次出现的顺序；K 为 0 时没有排名项；K 大于项目数时显示已有项目。
筛选函数新建列表，但列表里仍是原来的记录字典。本课的筛选和统计只读取这些字典，不修改字段。

六、带着本课成果进入第六课
保留整个学生练习文件夹，说明每个函数接收什么、返回什么、在哪里被调用。
下一课将用实验1保存的 network.log 和课堂模拟日志，组合完成级别、IP、设备、事件统计及阈值判断。
届时先使用提供的读取程序取得记录列表，文件解析的具体写法在后续课程中学习。
