来源: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: Beijing

1.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=81

1.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门课程的成绩 - 计算每个学生的平均分 - 找出每门课程的最高分

  1. B - range(0, 10, 2) 生成 0, 2, 4, 6, 8(不包含10)

  2. B - enumerate从start=1开始编号,输出 1: A 2: B 3: C

  3. C - zip会截断到最短序列的长度

  4. range(len(列表)) - for i in range(len(data))可以遍历索引

  5. 10, 8, 6, 4, 2 - 从10开始,步长-2,不包含0

enumerate:同时获取索引和值 - 适用于需要知道当前位置的场景 - 例如:打印带行号的内容、查找特定位置的元素 zip:并行遍历多个序列 - 适用于需要同时处理多个序列对应元素的场景 - 例如:合并两个列表、构建字典、并行迭代
# 方法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学习!明天我们将学习嵌套循环与图案打印,掌握复杂循环结构的运用。