哈佛免费 Python 课,FDE 最该精读第 5 周
CS50P 第 5 周讲 assert、pytest 和打包:代码要跑在客户数据上,还要交给别人接手,这是底线。
要点速览
- CS50P 由 David J. Malan 主讲。课程资料在 OpenCourseWare 上免费开放,没有先修要求,每周需投入 3–9 小时。
- 对想成为 FDE 的人来说,最值得细读的几周是异常、用 pytest 做单元测试、File I/O 和正则。
- 本轮课程于 2027 年 6 月 30 日结束,旧版本提交的作业可能不被认可,因此要在本轮内学完。
CS50P 的课程大纲从第 0 周排到第 9 周。对想成为前线部署工程师(FDE)的人来说,最值得投入精力的不是 OOP,也不是库,而是第 5 周:David J. Malan 在这一周讲 assert、AssertionError、pytest,以及如何用 __init__.py 把代码打包成 package。
原因在于这份工作本身。你在客户现场写的代码,要跑在不是你生成的数据上;你离开项目后,还得有人接手。
所以,带测试、错误处理得当的 Python 基础,对 FDE 来说是最低要求,而不是加分项。CS50P 教的正是这套基础。
谁来讲,课程怎么上?
课程全称是 CS50’s Introduction to Programming with Python,官网是 cs50.harvard.edu/python。哈佛对 Malan 的介绍是 Gordon McKay 计算机科学实践教授(Gordon McKay Professor of the Practice of Computer Science)。他从 2007 年起讲授 CS50。
据 Harvard PLL 介绍,课程为期 9 周,自定进度,每周需投入 3–9 小时。共十讲,编号 0 到 9。课程资料可在 OpenCourseWare 上免费观看;如果想拿证书,无论免费还是付费,都需要注册 edX 账号。
课程不要求编程经验,也不需要证明你学过任何前置课程。本轮课程于 2026 年 1 月 1 日开始,只有一个最终截止日期——2027 年 6 月 30 日,单项作业没有截止时间。
有一点要注意:新版本发布后,为旧版本提交的作业可能不再被认可。别学到一半拖到明年。
十讲内容,拼起来就是一项熟悉的 FDE 任务
十讲依次是函数与变量、条件语句、循环、异常、库、单元测试、File I/O、正则、OOP 和 Et Cetera,最后是期末项目。逐周看,这是一份很常见的清单;拼在一起,恰好对应一项再普通不过的 FDE 任务。
假设客户发来一份从老旧系统导出的 CSV。日期列有的地方写成 “2026-03-01”,有的地方写成 “01/03/2026”,还有几行填的是文字而不是日期。
处理这份文件,你需要用 File I/O(第 6 周)读取文件,用正则(第 7 周)识别两种格式,用异常(第 3 周)处理坏行,同时不让程序崩溃。
import re
def parse_date(s):
if m := re.fullmatch(r"(\d{4})-(\d{2})-(\d{2})", s):
y, mo, d = m.groups()
elif m := re.fullmatch(r"(\d{2})/(\d{2})/(\d{4})", s):
d, mo, y = m.groups()
else:
raise ValueError(f"无效日期:{s}")
return f"{y}-{mo}-{d}"
剩下的一步就是第 5 周:在拿真实数据跑之前,先写测试,把这个函数该有的行为固定下来。
import pytest
from parse import parse_date
def test_two_formats():
assert parse_date("2026-03-01") == "2026-03-01"
assert parse_date("01/03/2026") == "2026-03-01"
def test_bad_input():
with pytest.raises(ValueError):
parse_date("yesterday")
常见错误:正则匹配上了,日期却还是错的
两个测试都通过了,但函数仍有漏洞。输入 “99/99/2026”,正则照样能匹配,因为 \d{2} 只检查是不是两位数字,函数会把 “2026-99-99” 当成真实日期返回。
这是初学者写正则的典型错误:正则检查的是字符串的形状,而不是含义。修复办法是交给标准库去校验日期,再针对漏掉的这个情况补一条测试。
import re
from datetime import date
def parse_date(s):
if m := re.fullmatch(r"(\d{4})-(\d{2})-(\d{2})", s):
y, mo, d = m.groups()
elif m := re.fullmatch(r"(\d{2})/(\d{2})/(\d{4})", s):
d, mo, y = m.groups()
else:
raise ValueError(f"无效日期:{s}")
date(int(y), int(mo), int(d)) # 新增一行:日期不存在时抛出 ValueError
return f"{y}-{mo}-{d}"
新增的这一行会在日期不存在时抛出 ValueError。下面是针对漏网情况的新测试:
def test_nonexistent_date():
with pytest.raises(ValueError):
parse_date("99/99/2026")
练习:客户又发来一批 “1/3/2026” 这样不带前导零的数据。先写测试,期望结果为 “2026-03-01”;再加一条测试,确保 “31/02/2026” 会被拒绝;然后才去改正则和输出格式,直到所有测试通过。
从课程中带走的三个观念
第一,出错是常态。课程第 0 周的讲义说,bug 是编程的自然组成部分,是等你去解决的问题,并鼓励学习者不要因此气馁。
对 FDE 来说,这句话的含义更具体:坏数据一定会出现,所以上面的 raise ValueError 是一个设计决策,而不是临时补丁。
第二,测试是你和自己、和接手代码的人之间的约定。上面的测试准确描述了函数接受什么、拒绝什么。客户发来新格式时,先加一行 assert 再改代码,就能确定没有破坏原有格式。
第三,留给别人的代码必须打包。第 4 周讲如何使用库,第 5 周讲如何用 __init__.py 构建自己的 package。躺在 Downloads 文件夹里的一个脚本,和一个客户工程师在你离开项目后还能 import、能测试的 package,差别很大。
适合谁,按什么顺序学?
如果你有 2-8 年 Java、C# 或 JavaScript 经验,第 0–2 周用一两个晚上快速过一遍即可。
把时间留给第 3、5、6、7 周,这几周的每一套习题都要做,包括看起来很简单的。
零基础的学习者按原有顺序学,这门课本来就是为从没编过程的人设计的。
最值得投入的是期末项目。选一个接近真实客户工作的问题,比如一个清洗导出文件的工具,就像上面的例子,配上测试目录和说明运行方法的 README。写进简历时,按项目来描述(“支持 N 种数据格式,使用 pytest 测试”),而不是只写课程名。
证书方面,CS50 免费颁发自己的证书。edX 上另有付费认证证书,可以作为向雇主证明的材料。
无论选哪种,申请 FDE 岗位时,都应把项目仓库当作主要证据,证书只是辅助。让 tests/ 目录替你说话。
CS50P 不会把你变成 FDE。它能做到的是:客户第一次把一份杂乱的数据文件交给你时,你的第一反应是写测试,而不是直接跑、然后祈祷。
这篇文章对你有帮助吗?
感谢你的反馈!