课程进度 课程大纲 已发布 24/24 课
Python 基础
数据与集合
构建可靠的程序
使用对象建模
专业 Python
高级 Python
一个循环,一项任务
第 7 章为你介绍了名为列表、字典和集合的盒子。现在,Python 可以依次走过每个盒子,完成一项小任务。
- 取出一个 Python 获取一个值
- 完成任务 循环体开始运行
- 继续前进 重复操作,直到完成
直接获取你需要的值:
topics = ["Python", "Git", "SQL"]
for topic in topics:
print("Practice", topic)
如果还需要一个用于显示的编号,请使用 enumerate():
for number, topic in enumerate(topics, start=1):
print(number, topic)
输出:
1 Python
2 Git
3 SQL
start=1 会改变 enumerate() 生成的编号。它不会改变列表或列表中真正的索引。只有当数字索引本身就是任务的一部分时,才使用 range(len(topics))。
使用 zip() 配对两行数据
想象有两行卡片。zip() 先把两行中的第一张卡片夹在一起,再把第二张卡片夹在一起,依此类推。
- Python 55 分钟
- Git 25 分钟
- SQL 40 分钟
topics = ["Python", "Git", "SQL"]
minutes = [55, 25, 40]
print(list(zip(topics, minutes)))
输出:
[('Python', 55), ('Git', 25), ('SQL', 40)]
这里有一个重要的边界情况:普通的 zip() 会在最短的输入结束时停止。
print(list(zip(["Python", "Git", "SQL"], [55, 25])))
输出:
[('Python', 55), ('Git', 25)]
SQL 悄悄消失了。如果这会导致数据出错,请使用 zip(topics, minutes, strict=True)。在 Python 3.10 或更新版本中,当长度不同时,它会引发 ValueError。第 10 章将教你如何处理这个错误。
排序,但不要弄乱原来的架子
sorted() 会创建一个新列表。原列表保持不变。
minutes = [55, 25, 40]
ranked = sorted(minutes, reverse=True)
print(ranked)
print(minutes)
输出:
[55, 40, 25]
[55, 25, 40]
当 Python 应该比较每条记录中的某一部分时,可以使用一个简短的键函数:
def minutes_in(record):
return record["minutes"]
records = [
{"topic": "Python", "minutes": 40},
{"topic": "Git", "minutes": 25},
{"topic": "SQL", "minutes": 40},
]
print([record["topic"] for record in sorted(records, key=minutes_in, reverse=True)])
输出:
['Python', 'SQL', 'Git']
Python 的排序是稳定的:Python 和 SQL 的值相同,因此它们会保持原来的先后顺序。请以 key=minutes_in 的形式传入函数,不要加 ()。
简短提醒:minutes.sort() 会修改该列表,并返回 None。当你想要一个新结果,并且必须保持原来的架子不变时,请使用 sorted(minutes)。
推导式是小巧的集合制造机
- 原集合 20、35、50
- 可选的筛选条件 保留 30 或更大的值
- 新集合 35、50
minutes = [20, 35, 50]
long_sessions = [value for value in minutes if value >= 30]
topic_names = {name.strip().casefold() for name in [" Python ", "python", "Git"]}
lookup = {topic: value for topic, value in zip(["Python", "Git"], [20, 35])}
print(long_sessions)
print(sorted(topic_names))
print(lookup)
输出:
[35, 50]
['git', 'python']
{'Python': 20, 'Git': 35}
方括号创建列表;包含一个表达式的花括号创建集合;key: value 创建字典。好的推导式只包含一个显而易见的转换,或许再加一个简单的筛选条件。如果需要做出多项判断、输出消息或执行多次更新,请把它展开成普通循环。易于阅读比代码简短更重要。
创建一支学习巡游队伍
将这个完整项目保存为 study_parade.py。它会严格配对数据、对一个新列表排序、为结果编号,并检查源数据是否未被修改。
def make_records(topics, minutes):
return [
{"topic": topic, "minutes": duration}
for topic, duration in zip(topics, minutes, strict=True)
]
def minutes_in(record):
return record["minutes"]
def build_report(topics, minutes, target):
ranked = sorted(make_records(topics, minutes), key=minutes_in, reverse=True)
lines = []
for number, record in enumerate(ranked, start=1):
if record["minutes"] >= target:
status = "target met"
else:
status = "keep going"
lines.append(
f"{number}. {record['topic']}: "
f"{record['minutes']} minutes ({status})"
)
return lines
topics = ["Python", "Git", "SQL", "Testing"]
minutes = [55, 25, 40, 25]
topics_before = topics.copy()
report = build_report(topics, minutes, target=30)
assert topics == topics_before
assert report[0].startswith("1. Python")
print("Study parade")
for line in report:
print(line)
print("Source still:", topics)
运行 python3 study_parade.py。你应该会看到:
Study parade
1. Python: 55 minutes (target met)
2. SQL: 40 minutes (target met)
3. Git: 25 minutes (keep going)
4. Testing: 25 minutes (keep going)
Source still: ['Python', 'Git', 'SQL', 'Testing']
Git 仍排在 Testing 前面,因为它们的值相同,并且排序是稳定的。如果出现 AssertionError,就说明之前保证的某个事实已经不再成立。
三个小任务
- 使用
enumerate(start=1)为四种零食的名称编号。 - 尝试对三个名称和两个分数使用普通的
zip();然后添加strict=True,并记录错误类型。 - 在项目中添加一次 60 分钟的学习活动,然后使用推导式,只收集达到目标的主题。
准备好学习第 9 章了吗?
- 我可以直接循环遍历值。
- 我可以使用
enumerate()添加便于人们阅读的编号。 - 我可以解释为什么普通的
zip()可能会丢掉一个元素。 - 我可以使用
sorted(),而不修改源数据。 - 我可以保持推导式简洁,并在它变得拥挤时改用循环。
- 我运行了学习巡游项目,并看到所有断言都通过了。
接下来,你会把这些任务放进一些相互协作的小函数中,并学习每个函数可以在哪里看到它所使用的名称。