视频封面

视频元信息

  • 时长: 约 2 小时(本笔记部分时间戳为估计值,精确时间戳仅覆盖前 21 分钟)

本笔记中的 [~MM:SS] 表示根据转录文本内容顺序估算的时间点;[MM:SS] 为视频转录片段中提供的真实时间点。部分后期章节时间未在原始片段中提供,标注为约数。


TL;DR (100字以内)

本讲从 C 语言过渡到 Python,一种更高级的解释型语言。通过 hello world、拼写检查器和图像滤镜演示了 Python 的简洁性,然后涵盖了语法:函数、格式字符串、条件、循环、数据结构、异常、命令行参数和第三方库,强调掌握 C 语言后学习 Python 主要是一个模式识别的问题。


引言:为什么选择 Python? [01:18]

  • 与 C 相比,Python 是一种更高级的语言。
  • 在 C 中,你必须自己管理内存和许多底层细节;Python 为你处理了大部分这些工作,因此你可以专注于实际问题。
  • Python 拥有更大的库生态系统(其他人编写的代码),你可以轻松使用。
  • 真正的目标不仅仅是学习 Python,而是教会自己一门新语言——你在 C 中学到的基础知识将仍然有用。

理解:将 C 语言翻译成 Python 就是识别相似模式并填补空白,而不是从零开始。


Hello World 与解释型语言和编译型语言 [~01:38]

  • C 语言的 hello world 需要包含头文件、int main(void)、花括号、分号等。
  • Python 的 hello world 只有一行:
    print("hello, world")
    
  • 行末没有分号。
  • 不需要 \n —— print() 默认会添加换行符。
  • 函数名是 print,不是 printf。

运行 Python 代码

  • 文件扩展名是 .py 而不是 .c。
  • 命令:python hello.py —— 只需一步,没有单独的编译过程。
  • Python 是一种解释型语言(按惯例);C 是编译型语言。
    • clang 将源代码编译为机器码。
    • Python 解释器从上到下运行代码,并弄清楚每一行的作用,而不生成单独的机器码文件。

易错点: Python 历史上被称作“解释型”,但这是一种惯例,而不是语言的内在属性。在本课程中,你用 python file.py 运行 Python 程序,而不是 ./file。


Python 的强大:拼写检查器和图像滤镜 [06:05]

用 Python 重写习题集 5

  • C 语言的拼写器实现(dictionary.c)花了很多小时/天来编写。
  • Python 版本(dictionary.py)仅用几行代码就实现了 check、load、size、unload:
    words = set()
    def check(word):
        return word.lower() in words
    def load(dictionary):
        with open(dictionary) as file:
            words.update(file.read().splitlines())
        return True
    def size():
        return len(words)
    def unload():
        return True
    
  • Python 为你管理内存,所以 unload 只是返回 True。

理解:这是一个“炫耀”,因为讲师有 C 语言的解决方案作为小抄,但它展示了 Python 对于同样的逻辑可以多么简洁。

图像模糊和边缘检测

  • 使用 Python 图像库(PIL):
    from PIL import Image, ImageFilter
    before = Image.open("bridge.bmp")
    after = before.filter(ImageFilter.BoxBlur(10))
    after.save("out.bmp")
    
  • 边缘检测:
    after = before.filter(ImageFilter.FIND_EDGES)
    
  • 仅用 4 行 Python 代码就实现了之前习题集 4 中费力的图像处理功能。

Python 特性概述 [13:45]

  • Python 中有函数,就像 Scratch 和 C 中一样,但语法更简单。
  • print 与 printf:更容易记住,不需要 %s 占位符(可以使用格式字符串)。
  • 没有分号 —— Python 自己判断语句在哪里结束。
  • 换行是 print() 的默认行为;之后你可以更改。
  • Python 中库被称为模块或包。
  • CS50 库可以这样导入:
    import cs50
    # 或者
    from cs50 import get_string
    

易错点: 忘记 f-string 中的 f 前缀会导致字面花括号被打印出来,例如,print("{answer}") 并不会替换变量值。


获取用户输入和格式字符串 [17:14]

  • 获取名字并打印问候语的示例。

打印问候语的三种方式

  1. 使用 + 拼接:

    answer = get_string("What's your name? ")
    print("hello, " + answer)
    
    + 对字符串表示拼接。

  2. 给 print 多个参数:

    print("hello,", answer)
    
    print 默认在参数之间添加一个空格。

  3. f-string(格式字符串) —— 现代最常见的方式:

    print(f"hello, {answer}")
    
    字符串中的花括号会被变量的值替换。这称为变量插值。

  4. Python 也可以使用内置的 input() 函数:

    answer = input("What's your name? ")
    

理解:f-string 就像改进版的 printf;不用 %s,而是直接在字符串中写 {variable}。

类型推断

  • 在 Python 中,你不需要声明变量类型。
  • 解释器根据上下文推断类型。如果你给 answer = input(...) 赋值,它是字符串;如果你给 counter = 0 赋值,它变成 int。

易错点: 在 Python 中你可以稍后更改变量的类型(例如,将字符串转换为 int),但通过运算符隐式进行转换可能会导致意外结果(参见计算器示例)。


命名参数:sep 和 end [~22:00]

  • Python 函数可以接受位置参数(顺序重要)和命名参数(name=value)。
  • 官方 Python 文档位于 docs.python.org。
  • print 函数有命名参数:
    • sep —— 多个值之间的分隔符(默认是一个空格)。
    • end —— 在最后一个值之后追加的字符串(默认是 "\n")。

示例:

print("hello, world", end="!")

这会移除换行符,并打印 ! 代替。

易错点: 混合使用位置参数和命名参数时,位置参数必须在前,命名参数在后。

  • 引号:在 Python 中,单引号和双引号可以互换使用。风格指南通常建议使用双引号以与 C 保持一致。

变量和数据类型 [~26:00]

  • 创建变量:
    counter = 0   # 没有 int 关键字,没有分号
    
  • 递增:
    counter = counter + 1
    counter += 1
    
  • Python 没有 counter++ 或 counter--。
  • Python 中的基本数据类型:
    • bool —— 大写 True / False(不是 true/false)
    • float
    • int —— 任意精度(不会溢出)
    • str(string 的缩写)
    • 没有 char 类型 —— 单个字符就是长度为 1 的字符串。
    • 没有单独的 double 或 long 类型。

理解:Python 每个数字使用更多内存,所以程序员不用担心位宽。


数据结构概述 [~30:00]

  • Python 内置了高级数据结构:
    • set —— 唯一值,类似于数学集合。
    • dict(字典)—— 键/值对。
    • tuple —— 不可变的短列表,例如 (x, y)。
    • list —— 自动增长/收缩(像链表,但不需要手动内存管理)。
    • range —— 高效地生成一个数字范围。

计算器:input() 返回字符串和 int() 转换 [~32:00]

  • 使用 CS50 get_int 的基本计算器:
    from cs50 import get_int
    x = get_int("x: ")
    y = get_int("y: ")
    print(x + y)
    
  • 使用 Python 内置的 input():
    x = input("x: ")
    y = input("y: ")
    print(x + y)  # 这会拼接字符串!例如,1 + 2 = 12
    

易错点: input() 总是返回一个字符串,所以 + 运算符会拼接。你必须使用 int() 转换:

x = int(input(<span class="md-quote">"x: "</span>))
y = int(input(<span class="md-quote">"y: "</span>))

  • 用于 Python 的 CS50 库提供 get_string、get_int、get_float,在输入无效时会重新提示(不像普通 input)。
  • 你可以一次性导入多个函数:
    from cs50 import get_string, get_int, get_float
    

条件和缩进 [~38:00]

  • if 语句:
    if x < y:
        print("x is less than y")
    
  • 条件末尾必须要有冒号 :。
  • 缩进很重要:if 的主体必须缩进(惯例:4 个空格)。Python 不使用花括号。

易错点: 一致的缩进是强制性的。没有缩进,Python 会引发 IndentationError。风格上,4 个空格是标准。

  • if / else:
    if x < y:
        print("x is less than y")
    else:
        print("x is not less than y")
    
  • else if 写作 elif(不是 else if):

    if x < y:
        print("x is less than y")
    elif x > y:
        print("x is greater than y")
    else:
        print("x is equal to y")
    

  • 整数的比较与 C 语言相同。

  • 在 Python 中,字符串的比较直接使用 == 即可(不需要 strcmp):
    s = input("s: ")
    t = input("t: ")
    if s == t:
        print("Same")
    else:
        print("Different")
    

理解:在 C 中,字符串是 char *,所以 == 比较的是内存地址;Python 将字符串视为一等对象,所以 == 比较实际值。

or 和 in 关键字

  • agree.py 示例:
    s = input("Do you agree? ")
    if s == "Y" or s == "y":
        print("Agreed.")
    elif s == "N" or s == "n":
        print("Not agreed.")
    
  • 使用 in 和列表更简洁:
    if s in ["Y", "y"]:
        ...
    elif s in ["N", "n"]:
        ...
    
  • 规范化(Canonicalization):先将输入转换为小写以处理多种变体:
    s = input("Do you agree? ").lower()
    if s in ["y", "yes"]:
        print("Agreed.")
    elif s in ["n", "no"]:
        print("Not agreed.")
    

字符串比较和方法(面向对象编程) [~44:00]

  • Python 字符串有内置的方法(附加在对象上的函数)。
  • 示例:s.lower() 返回一个小写版本。
  • 这是 Python 作为面向对象语言的结果。对象包含数据和关联的方法(不像 C 的结构体只包含数据)。

理解:在面向对象编程中,“方法”是绑定到数据类型的函数。你使用点号表示法调用它,例如 s.lower()。

  • 允许方法链式调用:
    s = input("Do you agree? ").lower()
    

复制字符串 [~50:00]

  • 在 C 中,复制字符串需要 malloc、strcpy、空检查、free 等。
  • 在 Python 中,复制和转换字符串非常简单:
    s = input("s: ")
    t = s.capitalize()
    print(f"s: {s}")
    print(f"t: {t}")
    

循环:while、for、range [~52:00]

while 循环

i = 0
while i < 3:
    print("meow")
    i += 1

带列表的 for 循环

for i in [0, 1, 2]:
    print("meow")

带 range 的 for 循环

for _ in range(3):
    print("meow")
  • range(3) 生成值 0, 1, 2 —— 高效,一次一个。
  • 下划线 _ 是一个约定俗成的变量名,用于你不关心值的时候。

无限循环

while True:
    print("meow")
  • 使用 Ctrl+C 中断无限循环。

易错点: Ctrl+C 会导致 KeyboardInterrupt 错误消息,但这并不是你代码中的 bug;它就是中断本身。

定义函数

def meow(n):
    for _ in range(n):
        print("meow")
  • 你必须在调用函数之前定义它(或者使用 main() 函数并在底部调用它)。
  • 常见模式:
    def main():
        meow(3)
    
    
    def meow(n):
        for _ in range(n):
            print("meow")
    
    
    main()
    
  • if __name__ == "__main__": main() 在实际的库代码中会使用,但本课程简化掉了。

易错点: 如果你定义了 main 但忘记在底部调用 main(),程序什么也不做。


数值边界情况:除法、浮点数精度、溢出 [~1:02:00]

除法

  • x / y 返回浮点结果(例如,1/3 = 0.333...)。
  • x // y 给出整数(截断)除法,就像 C 的 /。

浮点不精确

z = 1 / 3
print(f"{z:.50f}")
  • 即使是 Python 也有有限的精度;你仍然会得到很长的重复小数(不是真正无限)。像 decimal 这样的库可以提供帮助。

整数溢出

  • Python 整数可以任意大——没有整数溢出。

理解:Python 在需要时自动分配更多位,所以你永远不必考虑 32 位与 64 位的限制。


异常和 try/except [~1:08:00]

  • int("cat") 会引发 ValueError(一种异常),而不是返回一个哨兵值。
  • 异常比哨兵值更好,因为你不必牺牲一个有效值(例如,用 0 来表示失败)。

处理异常

try:
    n = int(input("n: "))
except ValueError:
    print("Not an integer")
  • 只包裹可能引发异常的那一行,而不是所有代码。
  • 使用 try/except 的 else 子句在未发生异常时运行代码:
    try:
        n = int(input("n: "))
    except ValueError:
        print("Not an integer")
    else:
        print("Integer")
    
  • CS50 的 get_int 使用带有 try/except 的循环,在输入有效之前不断重新提示。

Mario 示例:循环和字符串乘法 [~1:15:00]

竖直列

for _ in range(3):
    print("#")

使用 CS50 get_int 提示高度

from cs50 import get_int

while True:
    n = get_int("Height: ")
    if n > 0:
        break

for _ in range(n):
    print("#")

水平行

for _ in range(4):
    print("?", end="")
print()

字符串乘法

print("?" * 4)

嵌套循环(3×3 网格)

for i in range(3):
    for j in range(3):
        print("#", end="")
    print()

一行代码

print("#" * 3)

列表和字典 [~1:22:00]

列表

  • scores = [72, 73, 33]
  • len(scores) 给出长度。
  • sum(scores) 给出总和。
  • scores.append(score) 添加到末尾。
  • scores += [score] 也可以(列表拼接)。

示例:

scores = []
for _ in range(3):
    score = get_int("Score: ")
    scores.append(score)
average = sum(scores) / len(scores)
print(f"Average: {average}")

搜索列表

names = ["Ulya", "David", "John Harvard"]
name = input("Name: ")
if name in names:
    print("Found")
else:
    print("Not found")

理解:in 执行线性搜索,但实现细节对你隐藏。

字典

  • dict = 哈希表(键/值对),Python 内置。
  • 字典列表的示例:
    people = [
        {"name": "Ulya", "number": "+1-617-495-1000"},
        {"name": "David", "number": "+1-617-495-1000"},
        {"name": "John Harvard", "number": "+1-949-468-2750"}
    ]
    
  • 搜索:

    for person in people:
        if person["name"] == name:
            print(f"Found: {person['number']}")
            break
    else:
        print("Not found")
    

  • 更好的方式:一个将名字映射到号码的字典:

    people = {
        "Ulya": "+1-617-495-1000",
        "David": "+1-617-495-1000",
        "John Harvard": "+1-949-468-2750"
    }
    if name in people:
        print(f"Found: {people[name]}")
    else:
        print("Not found")
    


CSV 文件输入/输出 [~1:35:00]

  • Python 有内置的 csv 模块,用于读写逗号分隔值文件。

使用 csv.writer 写入

import csv

file = open("phonebook.csv", "a")
name = input("Name: ")
number = input("Number: ")
writer = csv.writer(file)
writer.writerow([name, number])
file.close()

使用 with 自动关闭

with open("phonebook.csv", "a") as file:
    writer = csv.writer(file)
    writer.writerow([name, number])

使用 csv.DictWriter

with open("phonebook.csv",

生成时间:2026-09-10 17:16:22 生成平台:VideoNote www.xygy.top