开始 CS50P 尽管我已经写 Python

2026年8月16日 learningpython

这个月开始 CS50P 感觉有点向后,tbh。我已经运送了一个 Django CRM,一个相机脚本给我发电子邮件,一个新闻摘要,一些抓取和 PDF 工具,两个 boot.dev 项目(bookbot、webflyx)。CS50P 是"Python 入门"课程。我已经知道 for 循环是什么。

我不管怎样做了,我很高兴我做了,四周了。

什么基础课程实际上检查

不是你是否可以写一个 for 循环。是你是否可以写一个另一个人,或 check50,或六个月从现在的未来我,可以实际上读和信任的。CS50P 的 test_ 文件约定,真的写真实的 pytest 测试而不是在终端中眼球输出,是事情有点让我尴尬。我已经写了"真实"脚本一阵子而测试基本上它们都没有。

我写的第一个测试文件,技术上通过和证明了什么都没有

那周的任务有我写一个小输入验证函数,检查一个牌子式代码遵循一组格式化规则,和写测试沿着它。我第一遍在测试文件看起来像这样:

from project import is_valid

def test_valid():
    assert is_valid("CS50P")

def test_invalid():
    assert not is_valid("cs50p")

两个测试。两个都通过了。绿色复选标记,感觉很好大约四分钟,一直到 check50 运行它自己的隐藏测试对我的 is_valid 函数和失败了在一个输入我从来没有真的尝试过:一个牌子有一个数字在中间,像 AB12CD,我的函数不正确地接受。

:( is_valid rejects plates with a letter after a digit
    expected "False", not "True"

真正的问题,一旦我看了

# project.py,打破的版本
def is_valid(s):
    return s[:2].isalpha() and s[2:].isalnum()

检查它以字母开始而其余是字母数字。不检查实际上顺序规则需要,那一旦一个数字显示向上,什么都不能跟随它。AB12CD 完全通过了这个检查:字母在开始,字母数字用于其余,技术上真的,错误的答案。

我自己的两个测试没有抓住这因为我只测试了一个显然有效的情况和一个显然无效的情况。两个都不在任何地方接近真正的边,那恰好是真实的 bug 躲藏的地方。

什么我实际上 google 了

"pytest test edge cases how many test cases is enough"最终导致我,对表驱动或参数化测试的思想,写一个案例列表向前(输入,预期结果)而不是一个 assert 一个时间,特别所以添加新的边界情况只是添加一行而不是写整个新函数。

import pytest
from project import is_valid

@pytest.mark.parametrize("plate, expected", [
    ("CS50P", True),
    ("cs50p", False),
    ("AB12CD", False),
    ("A1", False),
    ("", False),
])
def test_is_valid(plate, expected):
    assert is_valid(plate) == expected

五个案例而不是两个,并写它们出作为表做我自己的思考中的差距显然在 check50 不得不指向它给我。AB12CD 就在那里一旦我被迫真实上列出边界情况而不是拿两个感觉代表。

修复的函数

# project.py,修复的版本
def is_valid(s):
    seen_digit = False
    for ch in s:
        if ch.isdigit():
            seen_digit = True
        elif seen_digit:
            return False
    return len(s) >= 2 and s[:2].isalpha()

走字符串一次,一刻一个字母显示向上在一个数字已经被看到之后,它的无效。通过我扩展的本地测试和 check50 的隐藏的在下一次提交。

重新看到的重命名脚本

记起照片重命名脚本我写了一个阵子回,一个那个在第一次我运行它碰撞一个文件名冲突?我在一个 CS50P 讲座关于异常之后回去看它,而过去我已经包装什么都没有在一个尝试块中,只是让它崩溃和通过读 traceback 修复 bug。工作,技术上。不完全是推荐的方法。

旧重命名脚本,从这个课程让我思考失败模式之前

用新鲜的眼睛回去,修复不是真的关于异常重新,它是我从来没有一次考虑什么应该发生当重命名目标已经存在,只是曾经发现它通过看东西崩溃。一个 try/except FileExistsError 围绕实际的 os.rename 调用,降低到一个编号的后缀,会使第一版正确的在第一天而不是正确的在第四调试通过。

一个小的切线关于我争斗讲座视频的时间有多长而不是代码

真正失去大约四十分钟确信有一个 bug 在 pytest 本身,因为我参数化的测试持续报告错误的预期值在失败消息中,显示 False 当我确定我已经写了 True 对那行。没有 bug。我在列表的中间添加新情况时误数行并移动了每个后续的预期值一个,所以行四的牌子被检查对行五的预期回答。pytest 的错误消息是完全正确的整个时间。我只不相信它直到我打印了整个参数化列表出并通过手数像它是一个拼写测试。表驱动的测试只是像表一样值得信赖,这对后景是明显的而当时一点都不明显。

什么实际上这一次不同

我不学习语法。我已经有大多数那个,几乎意外,从只建立东西需要工作的事情。什么 CS50P 真的给我是东西没有人直接指向直到课程做:适当的库使用而不是复制粘贴堆栈溢出直到它编译,真实的测试纪律,代码那读起来像它被写给一个人和不只是对翻译器接受。

它是一个奇怪的种类的谦卑。bookbot 和 webflyx 两个工作了,运送了,做了东西他们应该做。两个都不会有幸存一个代码评审从某个实际上知道他们做什么,而我只真的相信那现在我已经看到什么替代看起来像,表驱动的测试包括。

什么我会不同地向前做

写边界情况的表在写函数之前,不之后。每个 bug 我已经在这个课程中打击是坐在差距之间"两个情况我想测试"和"情况 check50 实际上尝试了"。列出边界情况首先会变成那个差距进入什么我捕捉自己的,而不是什么一个分级脚本捕捉给我。

我也会停止信任一个绿色的测试运行作为任何东西本身的证明。两个通过的测试告诉我什么有用关于 is_valid,因为两个案例我拿是两个舒适远离规则的实际边。一个测试套房只好就像案例某个人实际上思考写那样好,我的包括,而"它通过了"是一个比声音更弱的句子像第一次你输入它。

我是否会实际上保持为每个一次性脚本在课程结束后写测试是分开的问题。问我在几个月里。我的诚实猜测现在是:对相机脚本和新闻摘要,可能是的,因为那些运行无人值守我不会在那里注意一个默认失败。对一个一次性的抓取我运行一次并扔掉,可能仍然没有,而我不确定那真的是错误的电话。

0 条评论

登录 后即可评论。

登录

忘记密码?

还没有账号?