哈佛CS50P课程的第四周专注于"资源库(Libraries)"主题,教授如何利用Python标准库和第三方包来提高开发效率。本文将详细介绍这一周的核心内容。

一、核心理念:代码复用

1. 为什么要使用资源库

David Malan教授指出:编程不应该总是从零开始。资源库是别人(或自己)编写的代码文件,旨在通过模块化(Modules)鼓励代码复用,避免机械的复制粘贴。

1
2
3
4
5
6
7
8
# 不推荐:重复造轮子
def calculate_circle_area(radius):
import math
return math.pi * radius ** 2

# 推荐:使用已有的模块
import math
area = math.pi * 5 ** 2

2. 模块化的优势

  • 代码复用:避免重复编写相同的代码
  • 维护性好:集中管理,便于更新
  • 可读性高:代码结构清晰,易于理解
  • 协作方便:团队成员可以共享使用

二、导入的艺术:import vs from

1. import模块

1
2
3
4
5
6
# 导入整个模块
import random

# 调用函数时需要带前缀
random_number = random.randint(1, 10)
random_choice = random.choice(["apple", "banana", "cherry"])

2. from...import

1
2
3
4
5
6
# 精确导入
from random import choice, randint

# 可以直接使用函数名
number = randint(1, 10)
item = choice(["a", "b", "c"])

3. 两者的选择

1
2
3
4
5
6
7
8
9
10
# import模块:避免命名冲突
import random
import mymodule

random.choice([1, 2]) # 明确是random模块
mymodule.choice([1, 2]) # 明确是mymodule模块

# from...import:代码更简洁
from random import choice
choice([1, 2, 3]) # 直接使用

三、Python标准库

1. random模块

1
2
3
4
5
6
7
8
9
10
11
12
import random

# choice: 随机选择
print(random.choice(["apple", "banana", "cherry"]))

# randint: 随机整数(闭区间)
print(random.randint(1, 10)) # 1到10之间的随机整数

# shuffle: 洗牌
cards = [1, 2, 3, 4, 5]
random.shuffle(cards)
print(cards) # 随机排序

2. statistics模块

1
2
3
4
5
6
7
8
import statistics

numbers = [1, 2, 3, 4, 5]

print(statistics.mean(numbers)) # 平均值:3
print(statistics.median(numbers)) # 中位数:3
print(statistics.mode(numbers)) # 众数:1
print(statistics.stdev(numbers)) # 标准差

3. sys模块

1
2
3
4
5
6
7
8
9
10
11
12
import sys

# sys.argv: 命令行参数
# python script.py arg1 arg2
# sys.argv = ['script.py', 'arg1', 'arg2']

# sys.exit: 退出程序
if len(sys.argv) < 2:
print("Usage: python script.py <name>")
sys.exit(1)

# sys.exit(0)表示正常退出,非0表示异常退出

四、第三方包与pip

1. pip包管理器

1
2
3
4
5
6
7
8
9
10
11
# 安装包
pip install requests

# 升级包
pip install --upgrade requests

# 卸载包
pip uninstall requests

# 查看已安装的包
pip list

2. PyPI:Python包索引

PyPI(Python Package Index)是Python第三方包的大本营,拥有超过40万个包。

1
2
3
4
5
6
# 安装常用包
pip install requests # HTTP请求
pip install numpy # 科学计算
pip install pandas # 数据分析
pip install matplotlib # 数据可视化
pip install pytest # 单元测试

3. cowsay趣味示例

1
2
3
4
5
6
7
8
# 安装cowsay
pip install cowsay

# 使用
import cowsay

cowsay.cow("Hello, World!")
cowsay.trex("Rawr!")

4. requests库实战

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import requests
import json

# 发送HTTP请求
response = requests.get("https://itunes.apple.com/search", params={
"term": "Taylor Swift",
"limit": 5
})

# 解析JSON响应
data = response.json()

# 处理数据
for track in data["results"]:
print(f"{track['trackName']} - {track['artistName']}")

五、开发者素养:编写自己的库

1. 创建模块

创建mymodule.py

1
2
3
4
5
6
7
8
9
10
11
# mymodule.py

def greet(name):
"""问候函数"""
return f"Hello, {name}!"

def farewell(name):
"""告别函数"""
return f"Goodbye, {name}!"

__version__ = "1.0.0"

2. 使用自己的模块

1
2
3
4
import mymodule

print(mymodule.greet("Alice"))
print(mymodule.farewell("Bob"))

3. if name == "main":

1
2
3
4
5
6
7
8
9
10
11
12
# mymodule.py

def greet(name):
return f"Hello, {name}!"

# 测试代码
if __name__ == "__main__":
# 只有直接运行此文件时才会执行
print(greet("World"))
print("模块测试中...")

# 当作为模块导入时,if __name__ == "__main__"下的代码不会执行

六、进阶技巧:切片(Slices)

1. sys.argv切片

1
2
3
4
5
6
7
8
9
10
import sys

# sys.argv[0] 是脚本名
# sys.argv[1:] 是实际参数

# 处理命令行参数
args = sys.argv[1:]

for arg in args:
print(arg)

2. 列表切片

1
2
3
4
5
6
7
numbers = [0, 1, 2, 3, 4, 5]

print(numbers[1:4]) # [1, 2, 3]
print(numbers[:3]) # [0, 1, 2]
print(numbers[3:]) # [3, 4, 5]
print(numbers[::2]) # [0, 2, 4]
print(numbers[::-1]) # [5, 4, 3, 2, 1, 0]

七、综合示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
CS50P Week4 综合示例
"""

import random
import statistics
import sys
from datetime import datetime

def random_number_game():
"""猜数字游戏"""
print("=== 猜数字游戏 ===")

target = random.randint(1, 100)
attempts = 0

while True:
guess = input("请输入1-100之间的数字(输入q退出):")

if guess.lower() == 'q':
print("游戏结束")
break

try:
guess = int(guess)
except ValueError:
print("请输入有效的数字")
continue

attempts += 1

if guess < target:
print("太小了,再试一次!")
elif guess > target:
print("太大了,再试一次!")
else:
print(f"恭喜你,猜对了!用了{attempts}次机会")
break

def statistics_demo():
"""统计示例"""
print("\n=== 统计分析 ===")

scores = [85, 92, 78, 95, 88, 76, 90, 82]

print(f"分数列表: {scores}")
print(f"平均分: {statistics.mean(scores):.2f}")
print(f"中位数: {statistics.median(scores):.2f}")
print(f"最高分: {max(scores)}")
print(f"最低分: {min(scores)}")
print(f"标准差: {statistics.stdev(scores):.2f}")

def command_line_args():
"""命令行参数示例"""
print("\n=== 命令行参数 ===")
print(f"脚本名: {sys.argv[0]}")

if len(sys.argv) > 1:
print(f"参数数量: {len(sys.argv) - 1}")
for i, arg in enumerate(sys.argv[1:], 1):
print(f" 参数{i}: {arg}")
else:
print("没有提供参数")

def main():
"""主函数"""
print(f"程序运行时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")

random_number_game()
statistics_demo()
command_line_args()

if __name__ == "__main__":
main()

八、学习建议

1. 多使用官方文档

Python的官方文档是最权威的学习资源,访问docs.python.org获取最新信息。

2. 学会阅读文档

即使文档不清晰,也要学会探索:

  • 查看函数的参数和返回值
  • 阅读示例代码
  • 尝试运行示例

3. 防御性编程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 处理可能的异常
import sys

if len(sys.argv) < 2:
print("Usage: python script.py <filename>")
sys.exit(1)

filename = sys.argv[1]

# 处理文件不存在的异常
try:
with open(filename, 'r') as f:
content = f.read()
except FileNotFoundError:
print(f"文件 '{filename}' 不存在")
sys.exit(1)