Python(for循环)

1.了解for循环

1. 什么是 for 循环?

在许多语言中(如 C、Java),for 循环是基于计数器的:

C语言

复制代码
int main()
{
    for(int i = 0; i < 10 ; i++)
    {
        printf("%d\n",i);
    }
}

但 Python 的 for 完全不同:它是迭代器风格的循环,直接遍历一个可迭代对象中的每个元素,而不需要手动管理索引。

Python

复制代码
for item in [1, 2, 3, 4, 5]:
    print(item)

这种设计的优点:

  • 简洁:不需要写索引、边界条件、步长。

  • 安全:不会出现"差一错误"(off-by-one error)。

  • 通用:可以遍历任何可迭代对象(列表、字符串、字典、文件、生成器等)。

2. 可迭代对象与迭代器

  • 可迭代对象 :凡是可以用 for...in 直接循环的对象,如列表、元组、字符串、字典、集合、文件对象、range、生成器等。

  • 迭代器 :实现了 __next__() 方法的对象,可以逐个产生元素。for 循环内部会自动将可迭代对象转换成迭代器,然后反复调用 __next__() 直到捕获 StopIteration 异常。

你可以手动模拟 for 循环的行为:

复制代码
fruits = ["苹果", "香蕉", "橙子"]
iterator = iter(fruits)   # 获取迭代器
while True:
    try:
        fruit = next(iterator)
        print(fruit)
    except StopIteration:
        break

3. for 循环的语法结构

复制代码
for 变量 in 可迭代对象:
    循环体代码块
else:
    循环正常结束(没有被 break 打断)时执行
  • 变量:每次循环被赋值为可迭代对象中的下一个元素。

  • 循环体:缩进的代码块,对每个元素执行一次。

  • else 子句(可选):仅在循环没有被 break 终止时执行。通常用于"如果没找到"的场景。

    for i in range(3):
    print(i)

    输出:0 1 2

2.代码执行顺序

1. 基本执行流程

复制代码
for i in [10, 20, 30]:
    print("开始循环")
    print(i)
    print("结束本次循环")
print("循环结束")

执行顺序:

  1. 将可迭代对象 [10,20,30] 转换成迭代器。

  2. 取出第一个元素 10,赋值给 i

  3. 执行循环体(print("开始循环")print(10)print("结束本次循环"))。

  4. 回到迭代器,取出下一个元素 20,赋值给 i,再次执行循环体。

  5. 重复直到迭代器耗尽(抛出 StopIteration)。

  6. 跳出循环,执行 print("循环结束")

2. range 对象的惰性求值

range(start, stop, step) 不会一次性生成所有数字,而是返回一个惰性的 range 对象,它只在迭代时逐个生成数字。这节省内存,尤其适合大范围循环。

复制代码
for i in range(10**9):   # 不会占用大量内存
    if i == 5:
        break

3. 循环中改变可迭代对象的风险

不要在遍历列表的同时修改列表长度(添加或删除元素),这会导致元素被跳过或重复迭代。

复制代码
lst = [1, 2, 3, 4]
for x in lst:
    if x % 2 == 0:
        lst.remove(x)   # 危险!跳过某些元素
print(lst)   # 可能得到 [1, 3] 还是 [1, 3, 4]?取决于实现,不可预测。

正确做法:遍历副本 for x in lst[:]: 或者用列表推导式创建新列表。

4. breakcontinueelse 的执行顺序

  • break:立即终止整个循环,跳过 else 子句

  • continue:跳过本次循环剩余代码,进入下一次迭代

  • else:仅在循环正常结束(没有遇到 break)时执行。

    for n in range(2, 10):
    for x in range(2, n):
    if n % x == 0:
    print(n, '=', x, '*', n//x)
    break
    else:
    print(n, '是素数')

输出会列出素数和合数。这里的 else 属于内层 for,当内层循环没有被 break 时执行。

5. 理解 for 循环对迭代器的隐式调用

for 循环实质上等价于:

复制代码
iterator = iter(iterable)
while True:
    try:
        var = next(iterator)
    except StopIteration:
        break
    else:
        # 循环体
        ...

了解这个等价关系有助于理解为什么在循环中对 iterable 进行某些操作(如重新赋值)不会影响迭代器。

3.遍历---多种方式遍历各自数据结构

1. 遍历列表、元组、字符串

复制代码
colors = ['红', '绿', '蓝']
for c in colors:
    print(c)

# 遍历字符串中的字符
for ch in "Python":
    print(ch)

2. 使用 enumerate() 同时获取索引和值

当需要知道当前元素的索引时,不要手动维护计数器,用 enumerate

复制代码
for idx, fruit in enumerate(['苹果', '香蕉', '橙子']):
    print(f"{idx}: {fruit}")   # 0: 苹果, 1: 香蕉, 2: 橙子

可以指定起始索引:enumerate(列表, start=1)

3. 遍历多个列表:zip()

同时遍历两个或多个等长的可迭代对象:

复制代码
names = ['Alice', 'Bob', 'Charlie']
scores = [85, 92, 78]
for name, score in zip(names, scores):
    print(f"{name} 得分 {score}")

如果长度不一致,zip 会以最短的为准。如果需要以最长为准,可以使用 itertools.zip_longest

4. 遍历字典

  • 遍历键:for key in dict:for key in dict.keys():

  • 遍历值:for value in dict.values():

  • 遍历键值对:for key, value in dict.items():

复制代码
person = {'name': '张三', 'age': 30, 'city': '北京'}
for k, v in person.items():
    print(f"{k} -> {v}")

5. 遍历文件对象

文件对象是可迭代的

复制代码
with open('file.txt') as f:
    for line in f:        # 不会一次性读入整个文件
        print(line.strip())

这是处理大文件最推荐的方式。

6.使用 range() 进行数字循环

虽然不常用,但你也可以用索引方式遍历列表:

复制代码
fruits = ['苹果', '香蕉', '橙子']
for i in range(len(fruits)):
    print(f"{i}: {fruits[i]}")

enumerate 更优。

7.反向遍历:reversed()

复制代码
for item in reversed([1, 2, 3]):
    print(item)   # 3,2,1

8.带条件的遍历:结合 if

可以在循环体内加条件,也可以使用生成器表达式过滤:

复制代码
# 方法1
for x in range(20):
    if x % 2 == 0:
        print(x)

# 方法2:先生成偶数列表再遍历
for x in (x for x in range(20) if x % 2 == 0):
    print(x)

# 方法3:使用 filter
for x in filter(lambda x: x % 2 == 0, range(20)):
    print(x)

4.性能、惯用法与常见陷阱

1. for 循环与 while 循环的选择

  • for 适用于遍历已知可迭代对象(元素个数明确或可迭代)。

  • while 适用于基于条件循环(不知道何时终止,例如用户输入直到合法)。

2. 列表推导式 vs for 循环

列表推导式是 for 循环的一种高效替代,用于生成新列表。它通常比等价的 for 循环更快,因为内部使用专用 C 级实现。

复制代码
# 慢
squares = []
for x in range(1000):
    squares.append(x**2)

# 快
squares = [x**2 for x in range(1000)]

3. 避免在循环中重复计算不变量

复制代码
# 不推荐
for i in range(len(data)):
    process(i, len(data))   # len(data) 每次都要计算

# 推荐
n = len(data)
for i in range(n):
    process(i, n)

4. 使用 itertools 模块实现更复杂的遍历

  • itertools.chain:将多个可迭代对象串联。

  • itertools.product:嵌套循环的笛卡尔积。

  • itertools.combinations / permutations:组合与排列。

  • itertools.cycle:无限循环遍历。

避免多层嵌套循环

复制代码
from itertools import product
for i, j in product(range(3), range(3)):
    print(i, j)   # 输出9对

5. 生成器函数与 yield ------ 自定义迭代器

当你需要复杂的遍历逻辑时,可以编写生成器函数:

复制代码
def fibonacci(n):
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b

for num in fibonacci(10):
    print(num)

6. for 循环的性能特性

  • Python 的 for 循环比 C 语言慢,因为每次迭代都要进行对象创建和类型检查。

  • 对于数值密集型循环,考虑使用 NumPy 向量化操作。

  • 对于纯 Python 循环,尽量将工作移动到内置函数(如 sum, map, filter)或列表推导式中。

7. 常见陷阱总结

陷阱 后果 解决方案
遍历时修改列表长度 跳过或重复元素 遍历副本 lst[:],或用列表推导式过滤
忘记 enumerate,手动维护索引 代码冗余,易出错 使用 enumerate
使用 range(len(lst)) 而不是直接遍历 不 Pythonic,且慢 直接用 for x in lst:enumerate
在循环中调用函数却没有缓存结果 重复计算,效率低 将不变结果提到循环外
误用 else 子句(以为每次都会执行) 逻辑错误 牢记 else 仅在无 break 时执行
在循环内定义大对象却未复用 浪费内存和 CPU 将定义移到循环外

感谢你的观看,期待我们下次再见!

相关推荐
lzqrzpt39 分钟前
LED驱动电源选型标准与工程应用技术要点解析
python·单片机·嵌入式硬件·物联网
Maiko Star1 小时前
Python核心语法——函数
开发语言·python
linzᅟᅠ1 小时前
README
人工智能·python
瓶中怪1 小时前
ROS2 机器人软件系统
linux·c++·python·ubuntu·vmware·ros2·机器人软件开发
满怀冰雪2 小时前
22_Runnable接口源码拆解_LCEL管道语法背后_invoke_stream_batch究竟做了什么
python·batch
大气的小蜜蜂2 小时前
基于Python+Django的健身房管理系统实现:核心亮点全流程解析
开发语言·python·django
赵民勇2 小时前
Python 协程详解与技巧总结
python
极光代码工作室3 小时前
基于YOLO目标检测的智能监控系统
python·深度学习·yolo·机器学习·计算机视觉
吃好睡好便好3 小时前
泰戈尔的诗歌7
学习·生活
-To be number.wan3 小时前
数据库系统 | 规范化理论
数据库·学习