Week 02:Python 进阶 + Linux 工作流
返回主线计划:USTC 统计学 AI / 量化 20 周成长计划
本文命令默认使用 fish shell。如果你在 VS Code 终端里看到的不是 fish,可以先执行 fish 进入 fish;后续不再重复说明。目标不是把 Linux 背熟,而是把“写脚本、运行脚本、查看结果、提交 Git”变成稳定流程。
0. 本周详细教学:语法、规范、验收
本节不是追加在尾部的复习,而是本周正文的入口。先读这里,再做后面的命令和项目。
0.1 本周真正要学会什么
| 维度 | 要求 |
|---|---|
| 知识点 | list/dict、模块、异常、argparse、pathlib、Git commit |
| 代码语法 | 能从空文件写出本周核心脚本,而不是只复制运行 |
| 程序规范 | 函数拆分、路径清楚、输入输出明确、错误能解释 |
| 交付物 | src/data_summary.py |
| 验收方式 | 从 fish 终端运行命令,得到可复查的文件或指标 |
0.2 代码语法精讲
下面的代码不是最终答案,而是本周必须理解的最小骨架:
from argparse import ArgumentParser
from pathlib import Path
parser = ArgumentParser()
parser.add_argument(“—input”, required=True)
args = parser.parse_args()
path = Path(args.input)
if not path.exists():
raise SystemExit(f”missing input: {path}”)
print(path.read_text(encoding=“utf-8”)[
])
读代码时按四步检查:输入从哪里来;中间变量的类型和 shape 是什么;函数或脚本输出什么;哪些错误应该显式报出来。
0.3 本周程序规范
- 所有路径用相对路径或 `pathlib.Path`,不要写死 `/home/miku/...`。
- 核心逻辑进 `src/`,notebook 只做探索和解释。
- 每个脚本能从 fish 终端运行,并在 README 写出命令。
- 输出必须落盘到 `reports/`、`figures/` 或 `outputs/`,不能只在屏幕上看。
0.4 本周练习分层
| 层级 | 任务 | 不合格表现 | 合格验收 |
|---|---|---|---|
| 最小练习 | 手写上面的最小骨架 | 只在 notebook 里运行 | 终端运行成功 |
| 标准练习 | 把逻辑拆成函数/模块 | 一个大脚本从头写到尾 | 至少 2 个函数,职责清楚 |
| 项目练习 | 生成本周交付物 src/data_summary.py | 只有屏幕输出 | 文件落盘,可复查 |
| 复盘练习 | 写 3 个错误和修复 | 只写“已解决” | 写清报错、原因、修复、预防 |
0.5 本周和主线的连接
- 回到总计划:USTC AI / Quant 练习手册
- 查详细练习索引:技术练习详解
- 查质量评分:最终质量门槛
1. 本周目标
完成 Week 02 后,你应该能独立做到:
- 用 list comprehension / dict comprehension 写简洁的数据转换代码。
- 把重复逻辑封装成函数,而不是把所有代码堆在一个文件里。
- 用
pathlib处理文件路径,避免手动拼接字符串路径。 - 写一个可从命令行运行的 CSV 汇总脚本
src/data_summary.py。 - 在 fish 终端里完成目录导航、文件检查、
uv run运行、Git status/add/commit。
文件布局
本周交付物建议放在:
week02-python-linux-workflow/
├── data/
│ └── scores.csv
├── notes/
│ └── week02-linux-git.md
├── src/
│ └── data_summary.py
├── .venv/
├── pyproject.toml
└── README.md
2. 前置要求
你需要已经完成 Week 01 的基础环境:
- CachyOS / Arch 系 Linux 可正常打开终端。
- VS Code 已安装,并能用
code .打开当前目录。 uv已安装。- Git 可用:
git --version能输出版本号。 - 知道 Python 基础变量、列表、字典、
for循环、if判断。
先检查工具:
python --version
uv --version
git --version
pwd
解释:
| 命令 | 作用 |
|---|---|
python --version |
查看当前终端能找到的 Python 版本 |
uv --version |
确认 uv 可用 |
git --version |
确认 Git 可用 |
pwd |
打印当前位置,避免在错误目录创建项目 |
3. 创建 Week 02 项目目录
建议每周一个独立项目,这样 Git 提交、依赖和报告都清楚。
mkdir -p ~/Code/python-learning/week02-python-linux-workflow
cd ~/Code/python-learning/week02-python-linux-workflow
mkdir -p src data notes reports
code .
逐句解释:
| 命令 | 含义 |
|---|---|
mkdir -p ... |
创建目录;如果上级目录不存在就一起创建 |
cd ... |
进入 Week 02 项目目录 |
mkdir -p src data notes reports |
创建源码、数据、笔记、报告目录 |
code . |
用 VS Code 打开当前项目 |
检查当前结构:
pwd
ls
你应该看到类似:
data notes reports src
4. 初始化 uv 项目和虚拟环境
在项目根目录执行:
uv init
uv venv
source .venv/bin/activate.fish
解释:
| 命令 | 作用 |
|---|---|
uv init |
生成 pyproject.toml、README.md、示例入口文件 |
uv venv |
创建当前项目专用虚拟环境 .venv/ |
source .venv/bin/activate.fish |
在 fish shell 中激活虚拟环境 |
激活后检查:
which python
python --version
如果 which python 输出路径包含当前项目的 .venv/bin/python,说明环境正确。
fish 注意:不要在 fish 里执行 Bash / Zsh 版本的虚拟环境激活脚本;fish 应使用
source .venv/bin/activate.fish。
本周需要 pandas 来读 CSV:
uv add pandas
之后运行脚本时优先使用:
uv run python src/data_summary.py --help
uv run 会自动使用项目环境,比“碰运气使用系统 Python”更稳。
5. fish 终端导航:从“知道在哪”开始
Linux 工作流第一件事不是命令多,而是永远知道自己在什么目录。
pwd
ls
cd src
pwd
cd ..
ls data
解释:
| 命令 | 作用 |
|---|---|
pwd |
打印当前目录 |
ls |
列出当前目录文件 |
cd src |
进入 src 子目录 |
cd .. |
回到上一级目录 |
ls data |
不进入 data,直接查看它里面有什么 |
常用路径写法:
| 写法 | 含义 |
|---|---|
. |
当前目录 |
.. |
上一级目录 |
~ |
当前用户主目录,例如 /home/miku |
~/Code |
主目录下的 Code 文件夹 |
src/data_summary.py |
当前目录下的相对路径 |
建议养成习惯:运行任何脚本前先看一眼:
pwd
ls
如果当前目录不是项目根目录,先 cd 回来:
cd ~/Code/python-learning/week02-python-linux-workflow
6. 创建练习 CSV 数据
可以先用 VS Code 新建 data/scores.csv,内容如下:
student,major,math,english,python
A,statistics,88,79,85
B,statistics,92,81,90
C,finance,75,86,78
D,finance,80,,82
E,statistics,95,88,
如果想用 fish 命令创建,也可以执行:
printf 'student,major,math,english,python\nA,statistics,88,79,85\nB,statistics,92,81,90\nC,finance,75,86,78\nD,finance,80,,82\nE,statistics,95,88,\n' > data/scores.csv
检查文件:
cat data/scores.csv
wc -l data/scores.csv
解释:
| 命令 | 作用 |
|---|---|
cat |
把整个小文件打印出来,适合查看短文件 |
wc -l |
统计行数;CSV 第一行表头也算一行 |
真实数据通常不建议用 cat 一次打印几万行。可以用:
head data/scores.csv
tail data/scores.csv
head 看开头,tail 看结尾。
7. Python 进阶一:list comprehension
list comprehension 适合把“循环生成新列表”的代码写得更清楚。
普通写法:
scores = [88, 92, 75, 80, 95] passed = []for score in scores: if score >= 80: passed.append(score)
print(passed)
list comprehension 写法:
scores = [88, 92, 75, 80, 95]
passed = [score for score in scores if score >= 80]
print(passed)
读法是:
[要放进新列表的值 for 临时变量 in 原列表 if 条件]
常见例子:
names = ["alice", "bob", "cathy"] upper_names = [name.upper() for name in names]scores = [88, 92, 75, 80, 95] labels = [“pass” if score >= 80 else “review” for score in scores]
raw_values = [“88”, “92”, "", “80”] clean_values = [int(value) for value in raw_values if value != ""]
注意:不要为了炫技把太复杂的逻辑塞进一行。如果一行里同时有多层循环、多层条件,普通 for 循环更适合。
8. Python 进阶二:dict comprehension
dict comprehension 用来从已有数据生成字典。
names = ["math", "english", "python"]
scores = [88, 79, 85]
score_dict = {name: score for name, score in zip(names, scores)}
print(score_dict)
输出:
{'math': 88, 'english': 79, 'python': 85}
筛选字典:
score_dict = {"math": 88, "english": 79, "python": 85}
high_scores = {subject: score for subject, score in score_dict.items() if score >= 80}
print(high_scores)
输出:
{'math': 88, 'python': 85}
在数据分析脚本中,dict comprehension 常用于生成摘要结果:
missing_counts = {column: 0 for column in ["math", "english", "python"]}
9. Python 进阶三:函数
函数的作用是把一段有明确职责的逻辑命名,方便重复使用和测试。
不推荐把所有逻辑写成这样:
import pandas as pd
df = pd.read_csv(“data/scores.csv”) print(df.shape) print(df.isna().sum()) print(df.mean(numeric_only=True))
更推荐拆成函数:
from pathlib import Pathimport pandas as pd
def load_csv(path: Path) -> pd.DataFrame: return pd.read_csv(path)
def summarize(df: pd.DataFrame) -> dict: return { “rows”: len(df), “columns”: len(df.columns), “missing_values”: int(df.isna().sum().sum()), “numeric_means”: df.mean(numeric_only=True).to_dict(), }
判断函数是否清楚,可以问三个问题:
- 函数名是否说明它做什么?
- 输入参数是否明确?
- 返回值是否明确?
对初学者来说,函数不需要一开始写得很抽象。先把“读取数据”“计算摘要”“打印摘要”拆开,就已经很好。
10. Python 进阶四:pathlib
pathlib 是 Python 处理路径的现代方式。
不要这样手动拼路径:
path = "data" + "/" + "scores.csv"
推荐这样:
from pathlib import Path
project_root = Path.cwd() data_path = project_root / “data” / “scores.csv” print(data_path)
常用方法:
| 写法 | 作用 |
|---|---|
Path.cwd() |
当前运行命令的目录 |
Path("data/scores.csv") |
创建相对路径对象 |
path.exists() |
判断路径是否存在 |
path.parent |
获取父目录 |
path.name |
获取文件名 |
path.suffix |
获取扩展名,例如 .csv |
在 CLI 脚本里,用户传入的路径建议立刻转成 Path:
csv_path = Path(args.csv)
11. 编写 CLI 脚本 src/data_summary.py
在 VS Code 中创建文件:
src/data_summary.py
写入下面代码:
from argparse import ArgumentParser from pathlib import Pathimport pandas as pd
def parse_args(): parser = ArgumentParser(description=“Summarize a CSV file.”) parser.add_argument(“csv”, help=“Path to the input CSV file”) return parser.parse_args()
def load_csv(path: Path) -> pd.DataFrame: if not path.exists(): raise FileNotFoundError(f”CSV file not found: {path}”) if path.suffix.lower() != “.csv”: raise ValueError(f”Expected a .csv file, got: {path}”) return pd.read_csv(path)
def build_summary(df: pd.DataFrame) -> dict: numeric_means = df.mean(numeric_only=True).to_dict() return { “rows”: len(df), “columns”: len(df.columns), “missing_values”: int(df.isna().sum().sum()), “numeric_means”: numeric_means, }
def print_summary(summary: dict) -> None: print(“CSV Summary”) print(”===========”) print(f”Rows: {summary[‘rows’]}”) print(f”Columns: {summary[‘columns’]}”) print(f”Missing values: {summary[‘missing_values’]}”) print(“Numeric column means:”)
plain for column, value in summary[“numeric_means”].items(): print(f”- {column}: {value:.2f}”)
def main() -> None: args = parse_args() csv_path = Path(args.csv) df = load_csv(csv_path) summary = build_summary(df) print_summary(summary)
if name == “main”: main()
这段脚本分成四层:
| 函数 | 职责 |
|---|---|
parse_args |
读取命令行参数 |
load_csv |
检查路径并读取 CSV |
build_summary |
计算行数、列数、缺失值、均值 |
print_summary |
把结果打印给用户 |
main |
串起完整流程 |
12. 运行 CLI 脚本
先看帮助:
uv run python src/data_summary.py --help
你应该看到脚本说明和参数说明。
再运行实际数据:
uv run python src/data_summary.py data/scores.csv
期望输出类似:
CSV Summary
===========
Rows: 5
Columns: 5
Missing values: 2
Numeric column means:
- math: 86.00
- english: 83.50
- python: 83.75
如果你已经激活虚拟环境,也可以运行:
python src/data_summary.py data/scores.csv
但为了可复现,本教程更推荐在说明文档里写 uv run python ...。
13. 常用 Linux 文件检查命令
本周不要求成为 Linux 专家,但这些命令会反复出现。
pwd
ls
cat data/scores.csv
head data/scores.csv
tail data/scores.csv
wc -l data/scores.csv
grep statistics data/scores.csv
解释:
| 命令 | 适合场景 |
|---|---|
pwd |
确认当前目录 |
ls |
看目录内容 |
cat |
查看很短的小文件 |
head |
查看文件开头 |
tail |
查看文件结尾 |
wc -l |
统计行数 |
grep statistics ... |
找包含 statistics 的行 |
复制、移动、删除文件要更谨慎:
cp data/scores.csv data/scores_backup.csv
mv data/scores_backup.csv data/scores_copy.csv
rm data/scores_copy.csv
解释:
| 命令 | 作用 | 风险 |
|---|---|---|
cp |
复制文件 | 可能覆盖同名文件 |
mv |
移动或重命名文件 | 可能把文件移到意外位置 |
rm |
删除文件 | 删除后通常不能轻松恢复 |
初学阶段,执行 rm 前先 ls 确认目标。
14. Git 基础:status / add / commit
在项目根目录初始化 Git:
git init
git status
git status 是最重要的 Git 命令之一。任何不确定的时候先运行它。
建议创建 .gitignore,避免把虚拟环境提交进去。在 VS Code 新建 .gitignore,写入:
.venv/
__pycache__/
.ipynb_checkpoints/
*.pyc
再次检查:
git status
把本周文件加入暂存区:
git add pyproject.toml uv.lock README.md .gitignore src data notes
git status
如果某个文件不存在,Git 会提示 pathspec 错误。可以先用 ls 看实际文件,再重新 git add 存在的文件。
提交:
git commit -m "Add week02 Python Linux workflow exercise"
提交后检查:
git status
git log --oneline -3
期望看到:
nothing to commit, working tree clean
以及最近提交列表中包含你的提交信息。
15. 写学习笔记 notes/week02-linux-git.md
在 VS Code 创建:
notes/week02-linux-git.md
建议包含四块:
# Week 02 Linux + Git 笔记
今天学会的命令
- pwd:查看当前目录
- ls:查看文件
- cd:切换目录
- uv run:用项目环境运行 Python
- git status:查看 Git 状态
今天写的脚本
- src/data_summary.py:读取 CSV,输出行数、列数、缺失值、数值列均值。
遇到的问题
- 问题:fish 中误用了 Bash 激活脚本。
- 解决:使用 source .venv/bin/activate.fish。
下次要改进
给脚本增加输出到 Markdown 文件的功能。
笔记不是为了凑字数,而是为了让两周后的你能复盘:当时怎么跑、哪里报错、怎么修。
16. 本周练习
练习 A:list comprehension
创建 src/comprehension_practice.py,完成:
- 给定分数列表
[58, 72, 81, 90, 45, 66],生成及格分数列表。 - 生成所有分数的平方列表。
- 把名字列表
['alice', 'bob', 'cathy']转成首字母大写。
运行:
uv run python src/comprehension_practice.py
练习 B:dict comprehension
创建科目到分数的字典:
subjects = ["math", "english", "python"]
scores = [88, 79, 85]
要求生成:
{'math': 88, 'english': 79, 'python': 85}
再筛选出分数大于等于 80 的科目。
练习 C:增强 data_summary.py
给脚本增加一个可选参数:
uv run python src/data_summary.py data/scores.csv --show-columns
当用户传入 --show-columns 时,额外打印列名。
提示:在 parse_args() 中增加:
parser.add_argument("--show-columns", action="store_true", help="Show CSV column names")
练习 D:Git 小循环
每完成一个小改动,就练习一次:
git status
git add src/data_summary.py
git commit -m "Improve data summary script"
git status
重点不是提交很多次,而是理解:工作区、暂存区、提交记录分别是什么。
17. 验收检查
在 Week 02 项目根目录执行:
pwd
ls
source .venv/bin/activate.fish
uv run python src/data_summary.py --help
uv run python src/data_summary.py data/scores.csv
git status
你应能确认:
pwd位于week02-python-linux-workflow项目目录。ls能看到src、data、notes、pyproject.toml。source .venv/bin/activate.fish不报错。uv run python src/data_summary.py --help能显示帮助。uv run python src/data_summary.py data/scores.csv能输出行数、列数、缺失值数量、数值列均值。git status能解释当前哪些文件未提交,或显示工作区干净。
18. 常见错误
错误 1:fish 中激活环境报语法错误
错误原因:执行了 Bash / Zsh 激活脚本。
fish 正确命令:
source .venv/bin/activate.fish
错误 2:ModuleNotFoundError: No module named 'pandas'
原因:当前环境没有安装 pandas,或没有使用项目环境运行。
修复:
cd ~/Code/python-learning/week02-python-linux-workflow
uv add pandas
uv run python src/data_summary.py data/scores.csv
错误 3:CSV file not found
原因:路径相对于当前目录解释,你可能不在项目根目录。
检查:
pwd
ls data
如果 data/scores.csv 不存在,就回到正确目录或重新创建文件。
错误 4:Git 把 .venv/ 也显示为待提交
原因:忘记写 .gitignore。
修复:
printf '.venv/\n__pycache__/\n.ipynb_checkpoints/\n*.pyc\n' > .gitignore
git status
如果 .venv/ 已经被 git add,先取消暂存:
git restore --staged .venv
错误 5:git commit 提示身份未知
Git 第一次提交可能要求配置姓名和邮箱。用你的真实或常用学习身份配置:
git config --global user.name "Miku"
git config --global user.email "miku@example.com"
然后重新提交。
19. 下一步
下一周进入 NumPy / Pandas。你会把本周的“能读 CSV 并打印摘要”升级成真正的数据处理流程:读取真实表格、处理缺失值、做分组统计、保存清洗后的数据,并为 Week 04 的 EDA 报告准备数据基础。
plain
気に入ったならばコメントを残してくださいね~