📋 前言
各位伙伴们,大家好!今天的学习内容非常特别,我们暂时从复杂的机器学习算法中抽身,回归到两个 Python 的基石上:元组 (Tuple) 和 os 模块。
你可能会问,这两者有什么关系?
- 元组 ,代表了程序内部数据的稳定性与契约精神。为什么深度学习框架如此偏爱它?
os模块 ,则是程序与外部世界(文件系统)沟通的桥梁与工具。如何让我们的代码不再局限于单个文件,而是能管理整个项目的数据?
今天,我们将通过一张"神图"彻底搞懂 Python 四大数据结构的使命,并学会使用 os 模块赋予我们的代码"探索"文件系统的能力。这对于我们未来处理大规模数据集、在服务器上工作至关重要。
一、再探数据结构:一张图搞懂 List, Tuple, Dict, Set 的天命
之前我们已经学习了多种数据结构,但可能还停留在"会用"的层面。今天,通过下面这张源自课程的总结图,我们将理解它们在机器学习/深度学习场景下的设计哲学和最佳实践。
| 数据结构 | 核心特点 | 机器学习/深度学习中的应用 |
|---|---|---|
| 列表 (List) | 可变 (Mutable)、有序、允许重复 |
收集训练过程中的指标 (losses.append(loss_value))、存储批次数据(转为 Tensor 前)、动态构建可变序列(如分词结果)。 |
| 元组 (Tuple) | 不可变 (Immutable)、有序、允许重复、可哈希 |
定义张量/数组的形状 (Shape) (batch_size, 224, 224, 3)、定义固定的超参数(如卷积核大小)、作为字典的键来缓存结果 cache[('conv', 32)]。 |
| 字典 (Dict) | 可变 (Mutable)、键值对、键唯一且不可变 |
存储超参数 ({'lr': 0.001}), 存储评估结果 ({'acc': 0.85}), 构建模型配置 (JSON)、建立标签与索引的映射 {'cat': 0, 'dog': 1}。 |
| 集合 (Set) | 可变 (Mutable)、无序、元素唯一且不可变 |
获取数据集中唯一的类别标签、对特征名列表去重、快速检查成员是否存在(比列表快得多)、比较不同数据集的特征集异同。 |
Aha! Moment:为什么元组如此重要?
通过上表,我终于豁然开朗:元组的核心价值在于它的"不可变性"。
在大型项目中,尤其是深度学习中,数据和参数的形状一旦确定,就不应该被意外修改。使用元组 (batch_size, height, width, channels) 来定义一个张量的形状,就像立下了一个"军令状",确保了后续所有操作的维度安全。
再回想昨天的 Pipeline: Pipeline([ ('scaler', StandardScaler()), ('model', LogisticRegression()) ])。
- 外层的
列表 []提供了步骤的顺序和可修改性(我们可以增删步骤)。 - 内层的
元组 ()则将步骤名和步骤对象牢牢"捆绑",这个对应关系是固定不变的。
这就是 Python 设计的精妙之处:用不同的数据结构来表达不同的"意图"。
二、程序的"眼睛"和"手":os 模块核心功能
如果说之前的代码都活在自己的小世界里,那么 os 模块就是它伸向外部真实文件系统的触手。这在处理图像数据集、管理模型文件、在无图形界面的服务器(如 Kaggle,
AutoDL)上工作时,是必备技能。
2.1 定位:我在哪?周围有什么?
os.getcwd(): 获取当前工作目录 (Get Current Working Directory)。os.listdir(path): 列出指定路径下的所有文件和文件夹名。
python
import os
current_dir = os.getcwd()
print(f"我现在在这里: {current_dir}")
dir_content = os.listdir(current_dir)
print(f"我周围有这些东西: {dir_content}")
2.2 导航:如何安全地构建路径?
永远不要手动拼接路径字符串! 比如 path = dir + '/' + file。这在 Windows 系统下会失效,因为 Windows 的路径分隔符是 \。
正确的做法是使用 os.path.join(),它会根据你的操作系统自动选择正确的分隔符。
python
path_part1 = 'data'
path_part2 = 'images'
filename = 'cat.jpg'
# 跨平台的、安全的方式
full_path = os.path.join(path_part1, path_part2, filename)
print(full_path)
# 在 Windows 上输出: 'data\\images\\cat.jpg'
# 在 Linux/macOS 上输出: 'data/images/cat.jpg'
2.3 探索:如何深度遍历整个文件夹?
这是 os 模块中最强大的功能之一:os.walk()。它就像一个勤劳的探险家,会深入你指定的目录,以及其中的每一个子目录,进行"深度优先"的遍历。
对于它访问的每一个目录,os.walk() 都会返回一个元组 (dirpath, dirnames, filenames):
dirpath: 当前目录的路径。dirnames: 当前目录下的子文件夹名称列表。filenames: 当前目录下的文件名称列表。
再次连接 :看,
os.walk()返回的核心信息就是一个元组,再次体现了元组用于承载一组固定结构数据的设计思想!
三、作业实践:打造一个命令行"目录树浏览器"
今天的作业是"对自己电脑的不同文件夹利用今天学到的知识操作下,理解下 os 路径"。让我们把这个作业做得更酷一点:编写一个函数,它可以像 Linux 的 tree 命令一样,可视化地打印出任何指定目录的结构。
这个练习将完美地结合 os.walk()、os.path.join() 和字符串操作。
我的代码实现
python
import os
def print_directory_tree(root_dir, indent_prefix=""):
"""
以树状结构打印出指定目录的文件和文件夹。
参数:
- root_dir: 要遍历的根目录路径。
- indent_prefix: 用于控制缩进的内部参数,调用时无需设置。
"""
# --- 准备工作:获取目录内容并排序 ---
try:
# 获取所有条目并过滤掉隐藏文件 (如 .git, .vscode)
items = [item for item in os.listdir(root_dir) if not item.startswith('.')]
items.sort() # 排序以获得一致的输出
except FileNotFoundError:
print(f"错误: 目录 '{root_dir}' 不存在。")
return
except PermissionError:
print(f"错误: 没有权限访问 '{root_dir}'。")
return
# --- 核心遍历逻辑 ---
for i, item in enumerate(items):
full_path = os.path.join(root_dir, item)
is_last = (i == len(items) - 1) # 判断是否是当前层的最后一个条目
# 打印当前条目的连接线和名称
connector = "└── " if is_last else "├── "
print(indent_prefix + connector + item)
# 如果是文件夹,则递归调用本函数,并更新下一层的缩进前缀
if os.path.isdir(full_path):
new_prefix = " " if is_last else "│ "
print_directory_tree(full_path, indent_prefix + new_prefix)
# --- 作业执行 ---
# 1. 选择一个你想要探索的文件夹路径
# 可以是你的项目文件夹、下载文件夹等
# 为了安全,请避免选择系统根目录 C:\ 或 /
# target_directory = r"D:\MyProjects\Python-60-Days" # Windows 示例
target_directory = './' # 使用当前目录作为示例
# 2. 开始打印目录树
print(f"🌳 目录树 for '{os.path.abspath(target_directory)}':")
print_directory_tree(target_directory)
运行结果(示例):
🌳 目录树 for 'G:\study\pythonstudy\my_project':
├── data
│ ├── processed
│ └── raw
│ └── data1.csv
├── main.py
├── README.md
└── src
├── models
│ └── model_a.py
└── utils.py
通过这个练习,我对 os.walk 的"深度优先"遍历有了极深的体感。代码一层层深入,就像剥洋葱一样,直到最深处,再回溯到上一层,继续探索其他分支。
四、总结与心得
Day 24 的学习让我收获了两个维度的成长:
-
深入理解了"不变"的力量:我不再认为元组是"功能受限的列表"。我明白了它的"不可变性"是一种强大的设计特性,是构建稳定、可预测程序的基石。在定义模型配置、函数返回值时,我会优先考虑使用元组。
-
获得了与系统交互的能力 :
os模块为我的代码打开了一扇通往外部世界的大门。我不再是只能处理内存中数据的"书呆子",而是可以编写脚本来自动整理文件、批量处理数据、为大型项目构建清晰的目录结构。 -
培养了"服务器思维" :老师强调的
os.walk()在无 GUI 环境下的重要性,让我提前有了在服务器上工作的意识。当面对只有命令行的 Linux 服务器时,这些工具就是我的眼睛和手,是必备的生存技能。
今天的学习,是编程内功的一次重要修炼。它让我们在攀登机器学习高峰的路上,步子迈得更稳、更扎实。
再次感谢 @浙大疏锦行 老师的精彩课程,将基础知识与高阶应用结合得如此完美!