来源:03_循环 hm_01~hm_05 + Python官方文档 + 网络资料整理
一、详细讲解
1.1 核心概念
for循环与range是Python编程中最常用和重要的迭代结构。在本课程的第8天,我们将系统学习for循环的基本语法、range函数的使用、enumerate和zip等内置函数的配合使用,以及序列解包在for循环中的应用。
for循环是一种基于迭代器的循环结构,它依次从可迭代对象中取出每个元素进行处理。与while循环不同,for循环不需要手动管理计数器,Python解释器会自动处理迭代的细节。这使得for循环更加简洁、安全,是处理已知序列或需要遍历元素场景的首选。
1.2 for循环语法详解
1.2.1 基本语法结构
# for循环的基本语法
for 变量 in 可迭代对象:
# 循环体
语句块
1.2.2 遍历各种序列类型
# 遍历字符串
print("=== 遍历字符串 ===")
for char in "Python":
print(char)
# 遍历列表
print("\n=== 遍历列表 ===")
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)
# 遍历元组
print("\n=== 遍历元组 ===")
coordinates = (10, 20, 30)
for coord in coordinates:
print(f"坐标: {coord}")
# 遍历字典(默认遍历键)
print("\n=== 遍历字典 ===")
person = {"name": "Alice", "age": 30, "city": "Beijing"}
for key in person:
print(f"{key}: {person[key]}")
运行结果:
=== 遍历字符串 === P y t h o n === 遍历列表 === apple banana cherry === 遍历元组 === 坐标: 10 坐标: 20 坐标: 30 === 遍历字典 === name: Alice age: 30 city: Beijing1.3 range函数详解
1.3.1 range函数语法
range(stop) # 0 到 stop-1
range(start, stop) # start 到 stop-1
range(start, stop, step) # start 到 stop-1,步长为step
1.3.2 range的基本使用
# range(stop) - 从0开始
print("range(5):", list(range(5)))
# 输出: [0, 1, 2, 3, 4]
# range(start, stop) - 指定起始和结束
print("range(1, 6):", list(range(1, 6)))
# 输出: [1, 2, 3, 4, 5]
# range(start, stop, step) - 指定步长
print("range(0, 10, 2):", list(range(0, 10, 2)))
# 输出: [0, 2, 4, 6, 8]
# 负数步长 - 倒序
print("range(10, 0, -1):", list(range(10, 0, -1)))
# 输出: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
# 负数步长 - 不包含结束值
print("range(10, 0, -2):", list(range(10, 0, -2)))
# 输出: [10, 8, 6, 4, 2]
1.3.3 range的常见用法
# 1~100累加求和
total = sum(range(1, 101))
print(f"1+2+...+100 = {total}") # 5050
# 生成指定长度的序列
print("range(10):", list(range(10)))
# 倒序遍历
for i in range(5, 0, -1):
print(f"倒计时: {i}")
print("发射!")
# 遍历列表的索引
colors = ["红", "绿", "蓝"]
for i in range(len(colors)):
print(f"第{i+1}个颜色: {colors[i]}")
1.4 enumerate函数详解
1.4.1 enumerate的基本语法
enumerate()函数用于在遍历序列时同时获取元素的索引和值。
enumerate(iterable, start=0)
# 返回: (索引, 值) 的元组
1.4.2 enumerate的使用示例
# 基本用法
fruits = ["apple", "banana", "cherry"]
for index, fruit in enumerate(fruits):
print(f"{index}: {fruit}")
# 输出:
# 0: apple
# 1: banana
# 2: cherry
# 指定起始索引
print("\n从1开始编号:")
for index, fruit in enumerate(fruits, start=1):
print(f"{index}: {fruit}")
# 输出:
# 1: apple
# 2: banana
# 3: cherry
1.4.3 enumerate的实际应用
# 应用1:同时遍历索引和值
scores = [85, 92, 78, 95, 88]
print("=== 成绩单 ===")
for i, score in enumerate(scores, 1):
status = "及格" if score >= 60 else "不及格"
print(f"第{i}名学生: {score}分 ({status})")
# 应用2:构建字典
names = ["Alice", "Bob", "Charlie"]
# 传统方式
name_dict = {}
for i, name in enumerate(names):
name_dict[i] = name
print(f"\n构建的字典: {name_dict}")
# 应用3:enumerate与条件判断
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print("\n=== 查找偶数 ===")
for i, num in enumerate(data):
if num % 2 == 0:
print(f"索引{i}: {num}是偶数")
1.5 zip函数详解
1.5.1 zip的基本语法
zip()函数用于将多个可迭代对象的对应元素打包成元组。
zip(iterable1, iterable2, ...)
# 返回: 迭代器,产生 (元素1, 元素2, ...) 的元组
1.5.2 zip的使用示例
# 基本用法 - 合并两个列表
names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 35]
print("=== 人员信息 ===")
for name, age in zip(names, ages):
print(f"{name}: {age}岁")
# 输出:
# Alice: 25岁
# Bob: 30岁
# Charlie: 35岁
# 合并多个列表
students = ["张三", "李四", "王五"]
math_scores = [85, 92, 78]
english_scores = [90, 88, 95]
print("\n=== 学生成绩表 ===")
print(f"{'姓名':<6} {'数学':<6} {'英语':<6}")
print("-" * 20)
for name, math, english in zip(students, math_scores, english_scores):
print(f"{name:<6} {math:<6} {english:<6}")
# 创建字典
keys = ["name", "age", "city"]
values = ["Alice", 30, "Beijing"]
person_dict = dict(zip(keys, values))
print(f"\n合并为字典: {person_dict}")
1.5.3 zip的注意事项
# zip会按照最短序列截断
list1 = [1, 2, 3, 4, 5]
list2 = ["a", "b", "c"]
result = list(zip(list1, list2))
print(f"不等长列表zip: {result}")
# 输出: [(1, 'a'), (2, 'b'), (3, 'c')]
# 使用zip_longest处理不等长序列(需要itertools)
from itertools import zip_longest
list1 = [1, 2, 3, 4, 5]
list2 = ["a", "b", "c"]
result = list(zip_longest(list1, list2, fillvalue=None))
print(f"zip_longest结果: {result}")
# 输出: [(1, 'a'), (2, 'b'), (3, 'c'), (4, None), (5, None)]
1.6 序列解包在for循环中的应用
1.6.1 基本解包
# 使用enumerate进行解包
pairs = [(1, "one"), (2, "two"), (3, "three")]
for number, word in pairs:
print(f"{number} -> {word}")
# 使用zip进行解包
keys = ["a", "b", "c"]
values = [1, 2, 3]
for k, v in zip(keys, values):
print(f"{k} = {v}")
1.6.2 使用*进行解包
# 使用 * 解包剩余元素
first, *middle, last = [1, 2, 3, 4, 5]
print(f"first={first}, middle={middle}, last={last}")
# first=1, middle=[2, 3, 4], last=5
# 在for循环中解包嵌套结构
students = [
("张三", [85, 90, 78]),
("李四", [92, 88, 95]),
("王五", [77, 82, 89])
]
print("\n=== 学生成绩 ===")
for name, scores in students:
avg = sum(scores) / len(scores)
print(f"{name}: 平均分 {avg:.1f}")
# 使用 enumerate 和解包
data = [10, 20, 30]
for i, (first, second) in enumerate(zip(data, data[1:])):
print(f"第{i}组: {first} + {second} = {first + second}")
1.7 for-else结构
与while循环一样,for循环也支持else子句。
# for-else语法
for 变量 in 可迭代对象:
循环体
else:
# 循环正常结束后执行
else语句块
# 示例:查找质数
def find_primes(n):
primes = []
for num in range(2, n + 1):
for i in range(2, int(num ** 0.5) + 1):
if num % i == 0:
break
else:
primes.append(num)
return primes
print(f"2-30之间的质数: {find_primes(30)}")
1.8 for循环的嵌套
# for循环嵌套:打印九九乘法表
print("=== 九九乘法表 ===")
for i in range(1, 10):
for j in range(1, i + 1):
print(f"{j}×{i}={i*j}", end="\t")
print() # 换行
输出:
=== 九九乘法表 === 1×1=1 2×1=2 2×2=4 3×1=3 2×3=6 3×3=9 4×1=4 2×4=8 3×4=12 4×4=16 5×1=5 2×5=10 3×5=15 4×5=20 5×5=25 6×1=6 2×6=12 3×6=18 4×6=24 5×6=30 6×6=36 7×1=7 2×7=14 3×7=21 4×7=28 5×7=35 6×7=42 7×7=49 8×1=8 2×8=16 3×8=24 4×8=32 5×8=40 6×8=48 7×8=56 8×8=64 9×1=9 2×9=18 3×9=27 4×9=36 5×9=45 6×9=54 7×9=63 8×9=72 9×9=811.9 实用示例
1.9.1 列表操作
# 列表去重(保持顺序)
def remove_duplicates(lst):
seen = set()
result = []
for item in lst:
if item not in seen:
seen.add(item)
result.append(item)
return result
numbers = [1, 2, 2, 3, 1, 4, 3, 5]
print(f"去重后: {remove_duplicates(numbers)}")
# 输出: [1, 2, 3, 4, 5]
# 列表过滤
def filter_even(numbers):
return [n for n in numbers if n % 2 == 0]
nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(f"偶数: {filter_even(nums)}")
# 输出: [2, 4, 6, 8, 10]
1.9.2 字符串处理
# 统计字符出现频率
text = "hello world"
char_count = {}
for char in text:
if char != " ": # 跳过空格
char_count[char] = char_count.get(char, 0) + 1
print("字符统计:")
for char, count in sorted(char_count.items()):
print(f"'{char}': {count}次")
# 反转字符串
original = "Python"
reversed_str = "".join(list(reversed(original)))
print(f"\n反转: {original} -> {reversed_str}")
1.9.3 数据聚合
# 按条件分组
students = [
{"name": "张三", "score": 85},
{"name": "李四", "score": 92},
{"name": "王五", "score": 78},
{"name": "赵六", "score": 88},
{"name": "钱七", "score": 95}
]
# 分组
excellent = []
good = []
passing = []
for student in students:
score = student["score"]
if score >= 90:
excellent.append(student["name"])
elif score >= 80:
good.append(student["name"])
else:
passing.append(student["name"])
print(f"优秀(>=90): {excellent}")
print(f"良好(80-89): {good}")
print(f"及格(60-79): {passing}")
1.10 最佳实践
1.10.1 优先使用内置函数
# 计算总和 - 使用sum而不是手动累加
numbers = [1, 2, 3, 4, 5]
total = sum(numbers) # 推荐
# total = 0
# for n in numbers:
# total += n # 不推荐
# 查找最大最小值
print(f"最大值: {max(numbers)}")
print(f"最小值: {min(numbers)}")
# 计数
print(f"元素个数: {len(numbers)}")
print(f"元素和: {sum(numbers)}")
print(f"平均值: {sum(numbers) / len(numbers)}")
1.10.2 使用列表推导式替代简单循环
# 生成平方数列表
n = 10
# 传统循环
squares = []
for i in range(1, n + 1):
squares.append(i ** 2)
print(f"平方数: {squares}")
# 列表推导式(更简洁)
squares = [i ** 2 for i in range(1, n + 1)]
print(f"平方数: {squares}")
1.10.3 合理使用生成器
# 对于大量数据,使用生成器节省内存
def square_numbers(n):
for i in range(n):
yield i ** 2
# 使用生成器
gen = square_numbers(1000000)
print(f"生成器对象: {gen}")
# 惰性求值 - 只在需要时计算
for i, sq in enumerate(square_numbers(10)):
print(f"{i}: {sq}")
if i >= 4:
break
1.11 常见错误与调试
# 错误1:修改正在遍历的列表
# numbers = [1, 2, 3, 4, 5]
# for n in numbers:
# if n == 3:
# numbers.remove(n) # 危险!可能导致跳过元素
# 正确做法:遍历副本
numbers = [1, 2, 3, 4, 5]
for n in numbers[:]: # 遍历副本
if n == 3:
numbers.remove(n)
print(f"删除后的列表: {numbers}")
# 错误2:忘记zip的不等长截断问题
# list1 = [1, 2, 3]
# list2 = ['a', 'b', 'c', 'd', 'e']
# for a, b in zip(list1, list2): # 只遍历到最短长度
# print(a, b)
# 正确做法:确保长度一致或使用zip_longest
二、背诵版
Day8 要点速记: 【for循环】 for 变量 in 可迭代对象: 循环体 # 自动从对象中取元素,不需要手动管理计数器 【range函数】 range(stop) # 0 ~ stop-1 range(start, stop) # start ~ stop-1 range(start, stop, step) # 按步长取值 【enumerate】 - 同时获取索引和值 for index, value in enumerate(序列, start=0): 处理 【zip】 - 并行遍历多个序列 for item1, item2 in zip(序列1, 序列2): 处理 【序列解包】 a, b, c = [1, 2, 3] first, *rest, last = [1, 2, 3, 4, 5] 【for-else】 for x in iterable: ... else: # 循环正常结束后执行 ...三、考前记忆
| 要素 | 内容 |
|---|---|
| 今日主题 | for循环与range |
| 关键词 | for、range、enumerate、zip、解包 |
| range参数 | range(起点,终点,步长) |
| enumerate返回值 | (索引, 值) 元组 |
| zip返回值 | (元素1, 元素2, …) 元组 |
| 重要考点 | range边界、enumerate解包、zip并行遍历 |
四、测试题
1. 单选题: 以下哪个range会生成序列 0, 2, 4, 6, 8?
- A. range(0, 9, 2)
- B. range(0, 10, 2)
- C. range(0, 8, 2)
- D. range(2, 10, 2)
2. 单选题: 以下代码的输出是什么?
for i, c in enumerate("ABC", start=1):
print(f"{i}: {c}")
- A. 0: A 1: B 2: C
- B. 1: A 2: B 3: C
- C. A:1 B:2 C:3
- D. 1:A 2:B 3:C
3. 单选题: zip函数在处理不等长序列时会怎么做?
- A. 报错
- B. 用None填充
- C. 截断到最短序列
- D. 无限延长
4. 填空题: 要遍历列表[1,2,3,4,5]的索引,应该使用 _______。
5. 填空题: range(10, 0, -2) 生成的序列是 _______。
6. 简答题: 请说明enumerate和zip的区别,以及它们的典型使用场景。
7. 代码题: 使用for循环和range计算1到100之间所有偶数的和。
8. 代码题: 使用zip合并两个列表,并创建一个字典: names = [“a”, “b”, “c”] values = [1, 2, 3]
9. 代码题: 使用enumerate找出列表中第一个负数的位置: data = [5, 3, 7, -2, 8, -1]
10. 综合题: 设计一个程序,模拟考试成绩统计: - 3个学生,4门课程的成绩 - 计算每个学生的平均分 - 找出每门课程的最高分
-
B - range(0, 10, 2) 生成 0, 2, 4, 6, 8(不包含10)
-
B - enumerate从start=1开始编号,输出 1: A 2: B 3: C
-
C - zip会截断到最短序列的长度
-
range(len(列表)) -
for i in range(len(data))可以遍历索引 -
10, 8, 6, 4, 2 - 从10开始,步长-2,不包含0
# 方法1:使用range的步长
total = sum(range(2, 101, 2))
print(f"偶数和: {total}")
# 方法2:使用条件判断
total = 0
for i in range(1, 101):
if i % 2 == 0:
total += i
print(f"偶数和: {total}")
names = ["a", "b", "c"]
values = [1, 2, 3]
# 使用zip创建字典
result_dict = dict(zip(names, values))
print(f"合并的字典: {result_dict}")
# 或者遍历方式
result_dict = {}
for name, value in zip(names, values):
result_dict[name] = value
print(f"合并的字典: {result_dict}")
data = [5, 3, 7, -2, 8, -1]
for index, value in enumerate(data):
if value < 0:
print(f"第一个负数在索引 {index}")
break
students = ["张三", "李四", "王五"]
scores = [
[85, 92, 78, 88], # 张三
[90, 85, 95, 82], # 李四
[78, 88, 80, 90] # 王五
]
courses = ["语文", "数学", "英语", "物理"]
# 计算每个学生的平均分
print("=== 学生平均分 ===")
for i, student in enumerate(students):
avg = sum(scores[i]) / len(scores[i])
print(f"{student}: {avg:.1f}分")
# 找出每门课程的最高分
print("\n=== 各科最高分 ===")
for j, course in enumerate(courses):
max_score = max(score[j] for score in scores)
top_student = students[scores[j].index(max_score)]
print(f"{course}: {max_score}分 ({top_student})")
五、扩展阅读
5.1 map和filter函数
# map:对每个元素应用函数
numbers = [1, 2, 3, 4, 5]
squares = list(map(lambda x: x ** 2, numbers))
print(f"平方: {squares}")
# filter:过滤满足条件的元素
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(f"偶数: {evens}")
# 组合使用
result = list(map(lambda x: x * 2, filter(lambda x: x > 2, numbers)))
print(f"大于2的数翻倍: {result}")
5.2 itertools模块
import itertools
# count: 无限计数器
# cycle: 无限循环迭代
# chain: 连接多个迭代器
# islice: 切片迭代器
# 使用islice模拟range的行为
result = list(itertools.islice(range(10), 0, 10, 2))
print(f"islice结果: {result}") # [0, 2, 4, 6, 8]
5.3 enumerate的高级用法
# 标记索引进行分组
data = ["a", "b", "", "c", "", "d", "e"]
groups = []
current_group = []
for i, item in enumerate(data):
if item:
current_group.append((i, item))
else:
if current_group:
groups.append(current_group)
current_group = []
if current_group:
groups.append(current_group)
print(f"分组结果: {groups}")
# 查找连续出现的模式
text = "aaabbbcccdddeee"
consecutive = []
current_char = text[0]
count = 1
for i in range(1, len(text)):
if text[i] == current_char:
count += 1
else:
consecutive.append((current_char, count))
current_char = text[i]
count = 1
consecutive.append((current_char, count))
print(f"连续字符: {consecutive}")
恭喜完成Day8学习!明天我们将学习嵌套循环与图案打印,掌握复杂循环结构的运用。