
视频元信息
- 时长:未提供(约为CS50标准讲座长度)
TL;DR
本讲从C语言过渡到Python,展示Python的简洁语法与高级抽象:无需编译、无指针、内置数据结构、异常处理等。通过重写拼写检查器和图像滤镜,对比了开发效率与运行性能的取舍,并演示了第三方库的安装与使用。
一、课程导语:为什么先学C再学Python
[45.1s] 本讲是第6周,正式从C语言转向Python。学习C的意义在于建立对计算机底层运作的自底向上理解——内存、指针、编译过程等。掌握这些后,学习Python、Java、C++、Swift等语言时,能真正明白它们“在做什么”。
- 理解:C语言提供了最接近硬件的抽象,而Python等高级语言隐藏了这些细节。先学C再学Python,能让你既会用工具,又懂工具的原理。
- 目标:CS50希望你在课程结束后,拥有“尝过”几种语言的能力,能够自学新语言——识别相似范式,遇到语法差异时知道去Google或问AI。
二、第一个Python程序:hello.py
[260.4s] 在C中,编译需要 make,运行 ./a.out;而Python中,直接运行 python hello.py 即可。Python本身既是语言也是程序,它逐行解释你的代码。
print("hello, world")
[298s] 与C对比,明显差异:
- 没有
#include、int main(void)、花括号 printf变成了print(更友好,但f-string仍保留格式化功能)- 不需要
\n—— print默认自动换行 - 不需要分号
易错点:Python中语句结尾不需要分号,但如果你写了分号,语法上也是允许的(不推荐)。不要习惯性地加C的分号。
三、Python与C的语法对比
1. 函数定义与库
- C:
#include <cs50.h>,使用头文件提供函数原型 - Python:使用
from cs50 import get_string或import cs50,更精确地导入所需功能 - Python中“库”称为模块(module)或包(package),包是模块的集合
2. 输入输出
C版本:
string answer = get_string("What's your name? ");
printf("hello, %s\n", answer);
Python版本:
answer = get_string("What's your name? ")
print("hello, " + answer)
- 加号
+用于字符串拼接(类似Scratch中的join积木) - 无需占位符
%s,也可以用f-string更显式地插值 - 变量无需声明类型,Python根据上下文自动推断
3. 更Pythonic的写法
answer = input("What's your name? ")
print("hello,", answer) # print可接收多个参数,默认用空格分隔
input是Python内置函数,替代get_string(训练轮)- f-string:
print(f"hello, {answer}"),花括号内变量会被插值(interpolate)
易错点:f-string必须在字符串前加
f,否则花括号内容不会替换,而是原样输出。例如print("hello, {answer}")会输出hello, {answer}。
4. 命名参数
- Python函数支持命名参数(named parameters),调用时可以不按顺序,通过名字指定参数值
- 例:
print("hello", end="")覆盖默认换行行为(默认end="\n") - 文档:
docs.python.org是官方权威文档,类似C的man pages
5. 引号灵活性
- Python中单引号
'...'和双引号"..."均可用于字符串,只需保持一致 - C中单引号只能用于字符,双引号用于字符串
四、用Python重写Pset5拼写检查器
[382.4s] 演示:用约19行Python代码(含空行)实现Pset5的拼写检查器(dictionary.py),核心是使用set数据类型,自动处理哈希表、去重、内存管理。
words = set()
def check(word):
return word.lower() in words
def load(dictionary):
with open(dictionary) as file:
words.update(file.read().split())
return True
def size():
return len(words)
def unload():
return True
- 理解:
set是Python内置数据结构,相当于自动实现的哈希表,无需自己管理冲突、扩容等 with open(...) as file自动关闭文件,避免内存泄漏return True表示成功,无需手动释放内存(Python垃圾回收)
性能对比:
- C实现:1.32秒
- Python实现:1.87秒
考点:Python代码开发效率高,但运行速度通常慢于编译型语言(C)。原因是C编译为机器码直接执行,而Python解释器逐行读取执行。不过Python内部会编译为字节码(bytecode)以提高效率。
五、用Python实现图像滤镜(PIL)
[774.5s] 使用Python图像库(PIL)几行代码实现Pset4的模糊和边缘检测。
模糊(blur.py):
from PIL import Image, ImageFilter
before = Image.open("bridge.bmp")
after = before.filter(ImageFilter.BoxBlur(10))
after.save("out.bmp")
边缘检测(edges.py):
from PIL import Image, ImageFilter
before = Image.open("bridge.bmp")
after = before.filter(ImageFilter.FIND_EDGES)
after.save("out.bmp")
- 理解:高级语言通过库将复杂算法封装成简单函数调用,大幅减少代码量
- 思考:这也体现了“不要重复造轮子”的工程思想,但底层原理(如卷积、滤波)仍值得理解
六、变量与数据类型
1. 变量声明
C:int counter = 0;
Python:counter = 0 (无类型、无分号)
2. 数据类型
- Python有:
bool,float,int,str(字符串) - 没有指针、没有
char*,也没有单独的char类型 - 没有指针意味着无法直接操作内存地址,避免了大量内存错误,但也失去了一些底层控制
3. 类型转换
x = int(input("x: "))
y = int(input("y: "))
print(x + y)
input返回字符串,必须用int()转换(convert),而非C中的“强制转换(cast)”,因为字符串底层是多个字符,需要解析
易错点:如果输入非数字(如“cat”),
int()会抛出ValueError异常,程序崩溃。需用异常处理或验证。
七、条件语句
C:
if (x < y)
{
printf("x is less than y\n");
}
else if (x > y)
{
printf("x is greater than y\n");
}
else
{
printf("x is equal to y\n");
}
Python:
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")
- 缩进是Python的语法要求,替代花括号
- 条件后需要冒号
: else if缩写为elif
易错点:Python强制缩进,不能随意把代码靠左对齐。缩进不一致会导致
IndentationError。这是语言设计上强制代码可读性的体现。
字符串比较
- Python中
==直接比较字符串内容,而非像C中比较指针地址 - Python的
==内部自动遍历字符,等价于C的strcmp循环
八、字符串操作与方法
1. 大小写转换
s.lower()返回小写版本s.upper()返回大写版本-
s.capitalize()首字母大写 -
理解:这些是字符串对象自带的方法(method),即“对象内部的函数”。这是面向对象编程(OOP)的体现——数据及其相关操作封装在一起。
2. 判断输入是否同意
s = input("Do you agree? ").lower()
if s in ["y", "yes"]:
print("Agreed")
else:
print("Not agreed")
in关键字检查元素是否在列表(list)中,比C中列举多个||条件更简洁- 链式调用:
input(...).lower()直接对返回值调用方法
九、循环
1. while循环
i = 0
while i < 3:
print("meow")
i += 1
- 无
++运算符,用i += 1 - 无限循环:
while True:
2. for循环
for i in range(3):
print("meow")
range(n)生成0到n-1的序列,且惰性求值,不一次性占用大量内存- 也可直接遍历列表:
for name in names: - 如果循环变量未使用,可用
_作为变量名(Pythonic约定)
3. 无do-while循环
Python没有do-while,但可用 while True + break 模拟:
while True:
n = int(input("Height: "))
if n > 0:
break
for i in range(n):
print("#")
- 理解:
break跳出循环,实现“至少执行一次”的效果
十、定义函数与main
1. 定义函数
def meow(n):
for _ in range(n):
print("meow")
- 用
def关键字,无需指定参数类型和返回类型 - 函数定义必须在使用之前(解释器逐行执行)
2. main函数约定
def main():
meow(3)
def meow(n):
for _ in range(n):
print("meow")
main()
- Python没有自动调用
main的机制,必须显式调用 - 更规范的做法:
if __name__ == "__main__":
main()
- 理解:这个条件判断允许文件被导入为模块时不执行主逻辑,而直接运行时才执行。这使代码更模块化。
易错点:忘记调用
main(),程序运行后不会有任何输出。这是初学者常犯错误。
3. 函数间空行
- Python风格指南(PEP8)建议函数之间用两个空行分隔
十一、数值问题
1. 截断(Truncation)
- Python中
7 / 3返回2.333...,自动进行浮点除法,不会像C中整数除法截断为2 - 旧式整数除法用
//:7 // 3得到2
2. 浮点精度
- Python仍存在浮点精度问题:
1 / 3显示0.3333333333333333,不是无限精确 - 原因:计算机用有限二进制位表示浮点数,无法精确表示某些十进制小数
- 可通过第三方库(如
decimal)获得更高精度
3. 整数溢出
- Python的整数可以无限增长,自动分配更多位,不存在C中
int溢出回绕的问题 - 这是Python相比C的一个重大优势,无需担心溢出边界
十二、异常处理
try:
n = int(input("x: "))
except ValueError:
print("Not an integer")
- 异常(exception)允许“带外”传递错误,而非依赖返回值
- 常见异常类型:
ValueError,NameError,ModuleNotFoundError等 - 可自定义异常,也可捕获多种异常
- CS50库中的
get_int内部就是用try/except实现重新提示
易错点:不要盲目捕获所有异常(
except:),应捕获具体异常类型,否则可能隐藏严重错误。
十三、数据结构
1. 列表(list)
- 类似C的数组,但动态增长,内部是链表或动态数组
- 支持
len()获取长度,append()添加元素,sum()求和
scores = []
scores.append(72)
scores.append(73)
scores.append(33)
print(f"Average: {sum(scores) / len(scores)}")
2. 元组(tuple)
- 不可变列表,用于固定集合(如坐标)
3. 字典(dict)
- 键值对集合,相当于哈希表
- 用字符串索引,如
people["David"]
people = {
"Carter": "+1-617-495-1000",
"David": "+1-617-495-1000"
}
name = input("Name: ")
if name in people:
print(f"Number: {people[name]}")
- 理解:字典的
in操作检查的是键是否存在,时间复杂度平均O(1)
4. 集合(set)
- 无重复元素的无序集合,用于成员检查
5. 列表与字典组合
- 列表的元素可以是字典,模拟表格数据(如电子表格中的行)
people = [
{"name": "Carter", "number": "+1-617-495-1000"},
{"name": "David", "number": "+1-617-495-1000"},
{"name": "John", "number": "+1-949-468-2750"}
]
- 遍历时,
person是每个字典,用person["name"]访问字段 - 思考:这正是数据库表中行(记录)的抽象,后续学数据库时会用到
十四、文件I/O与CSV
1. 基础文件写入
file = open("phonebook.csv", "a")
name = input("Name: ")
number = input("Number: ")
writer = csv.writer(file)
writer.writerow([name, number])
file.close()
- 用
open替代C的fopen,模式"a"表示追加 csv.writer处理CSV格式,避免手动拼接逗号
2. with 语句
with open("phonebook.csv", "a") as file:
writer = csv.writer(file)
writer.writerow([name, number])
with自动关闭文件,即使发生异常也会关闭,避免内存泄漏
3. DictWriter
with open("phonebook.csv", "a") as file:
writer = csv.DictWriter(file, fieldnames=["name", "number"])
writer.writerow({"name": name, "number": number})
- 使用字典写入,不依赖列顺序,更健壮
十五、命令行参数与退出状态
1. sys.argv
from sys import argv
if len(argv) == 2:
print(f"hello, {argv[1]}")
else:
print("hello, world")
argv是包含命令行参数的列表,argv[0]是程序名,argv[1]是第一个参数- 注意:
argv不包含python解释器本身,只包含脚本名及其后参数
2. sys.exit
import sys
if len(sys.argv) != 2:
print("Missing command-line argument")
sys.exit(1)
print(f"hello, {sys.argv[1]}")
sys.exit(0)
sys.exit(1)表示错误退出,sys.exit(0)表示成功,便于自动化测试
十六、第三方库安装与使用
1. pip
pip install cowsay安装第三方库- 示例:
cowsay.cow("This is CS50")在终端显示奶牛说话
2. 语音合成(pyttsx3)
import pyttsx3
engine = pyttsx3.init()
engine.say("This is CS50")
engine.runAndWait()
- 需在本地电脑运行,因为云端环境无法播放音频
3. 生成二维码(qrcode)
import qrcode
image = qrcode.make("https://youtu.be/xvFZjo5PgG0")
image.save("qr.png")
- 自建QR码生成器,无需在线服务
十七、总结
- Python用更少的代码实现相同功能,开发效率高
- 性能略低于C,但通常足够;Python社区通过字节码、JIT等技术优化
- 数据结构、异常处理、库生态让Python成为“瑞士军刀”
- 后续课程会继续探索更多语言和问题
关键标签:Python CS50 编程语言对比 解释型语言 数据结构 异常处理 文件I/O 第三方库 f-string 列表 字典
生成时间:2026-09-02 16:32:29 生成平台:VideoNote