while 循环与循环嵌套

while 循环与循环嵌套

本文档带你掌握条件循环与循环嵌套,从简单重复到复杂模式,让代码更有威力!

📋 内容导航

🎯 内容回顾

上一篇我们学会了 for 循环,它能帮我们轻松搞定"重复N次"的任务。但现实往往没那么理想 ------ 很多时候我们根本不知道要重复多少次

想象一下这些场景:

🎮 猜数字游戏

  • 玩家:"我猜50!"

  • 系统:"大了"

  • 玩家:"那25!"

  • 系统:"小了"

  • ...(不知道要猜几次才能中)

💬 聊天机器人

  • 用户说一句,机器人回一句

  • 直到用户说"再见"才结束

  • (不知道要聊多少轮)

🎰 抽奖系统

  • "再抽一次!"

  • "再抽一次!"

  • 直到中奖或金币花光

  • (完全看运气)

这些场景的共同点是:不知道什么时候结束,只知道结束的条件

这就需要本文的主角 ------ while 循环(条件循环)!

本文学习目标

目标 内容 实战项目
while 循环 条件为真就一直执行 改进猜数字游戏
循环嵌套 多层循环的执行逻辑 打印九九乘法表
输入验证 处理各种用户输入 健壮的猜数字游戏

while 循环

什么是 while 循环?

while 循环的中文意思是"当...时",它的逻辑很简单:

当条件为真,就重复执行代码块;条件为假,就结束循环。

这就像是:"只要还没吃饱,就继续吃" ------ 你不知道要吃多少口,只知道什么时候该停。

while vs if 的区别

语句 条件为真时 执行次数
if 执行一次 0次或1次
while 执行完再判断,反复执行 0次、1次或多次

记忆口诀if 是"看一眼就走",while 是"不达目的不罢休"!

while 语法

复制代码
 while 条件表达式:
     循环体
 else:
     条件为False时执行(可选)

示例:1到100求和

复制代码
 total = 0
 addend = 1
 while addend <= 100:
     total += addend
     addend += 1
 print('1到100各数相加的和 = ', total)  # 5050

对比 for 循环:

复制代码
 # for 循环版本
 total = 0
 for i in range(1, 101):
     total += i
 print(total)

什么时候用 while?

  • 循环次数不确定,但有明确的结束条件

  • 需要一直等待某个条件发生

示例:水仙花数

水仙花数:一个三位数,其各位数字立方和等于该数本身。

复制代码
 # while 版本
 num = 100
 while num <= 999:
     i = num // 100      # 百位
     j = num // 10 % 10  # 十位
     k = num % 10        # 个位
     if i**3 + j**3 + k**3 == num:
         print(num)
     num += 1
 ​
 # for 版本
 for n in range(100, 1000):
     i, j, k = n // 100, n // 10 % 10, n % 10
     if i**3 + j**3 + k**3 == n:
         print(n)

实战:改进猜数字游戏

复制代码
 import random
 ​
 secret = random.randint(0, 100)
 print("猜一个0-100之间的数字")
 ​
 guess = int(input("你的猜测:"))
 while guess != secret:
     if guess > secret:
         print("猜大了")
     else:
         print("猜小了")
     guess = int(input("再猜一次:"))
 ​
 print("恭喜猜对了!")

无限循环

复制代码
 while True:  # 永远为真,无限循环
     msg = input("说点啥(输入quit退出):")
     if msg == "quit":
         break  # 用break跳出循环
     print(f"你说了:{msg}")

什么时候用无限循环?

  • 服务器程序(7×24小时运行)

  • 游戏主循环

  • 需要一直等待用户输入

循环嵌套

循环嵌套就是在一个循环体中嵌入另一个循环。

执行流程:

  • 外层循环执行一次,内层循环执行完整的一轮

  • 外层循环再执行一次,内层循环再执行完整的一轮

  • 以此类推

打印九九乘法表

复制代码
 # 基础版本(有重复)
 for i in range(1, 10):
     for j in range(1, 10):
         print(f'{j}*{i}={i*j}', end='\t')
     print()
 ​
 # 优化版本(去重复)
 for i in range(1, 10):
     for j in range(1, i + 1):  # 关键:j的范围是1到i
         print(f'{j}*{i}={i*j}', end='\t')
     print()

输出:

复制代码
 1*1=1
 1*2=2   2*2=4
 1*3=3   2*3=6   3*3=9
 ...

格式化对齐

让输出更整齐:

复制代码
for i in range(1, 10):
    for j in range(1, i + 1):
        print(f'{j}*{i}={i*j:2}', end='  ')  # :2 表示占2位宽度
    print()

字符串格式化速查

格式 含义 示例
{:2} 宽度为2 55
{:>2} 右对齐 55
{:<2} 左对齐 55
{:0>2} 左边补0 505
{:.2f} 保留2位小数 3.141593.14

综合实战:健壮的猜数字游戏

复制代码
import random

def get_valid_number(prompt):
    """获取有效的数字输入"""
    while True:
        user_input = input(prompt)
        if user_input.isdigit():
            return int(user_input)
        print("请输入数字!")

# 游戏主程序
secret = random.randint(0, 100)
print("猜一个0-100之间的数字")

attempts = 0
while True:
    guess = get_valid_number("你的猜测:")
    attempts += 1
    
    if guess == secret:
        print(f"恭喜猜对了!用了{attempts}次")
        break
    elif guess > secret:
        print("猜大了")
    else:
        print("猜小了")

🎉 文档总结

一、核心知识点回顾

1. while 循环
特性 说明 示例
语法 while 条件: while i <= 100:
执行逻辑 条件为真就执行,执行完再判断 可能执行0次、1次或多次
适用场景 不知道循环次数,只知道结束条件 猜数字、用户输入验证
else子句 循环正常结束时执行(非break退出) while...else...

for vs while 选择指南

复制代码
┌─────────────────────────────────────────┐
│  需要循环吗?                              │
│     ├── 知道循环次数?                      │
│     │      └── 是 → 用 for                │
│     │           for i in range(10):       │
│     │                                     │
│     └── 不知道次数,只知道条件?             │
│            └── 是 → 用 while              │
│                 while 条件:               │
└─────────────────────────────────────────┘
2. 循环嵌套

执行规则:外层循环执行1次,内层循环执行完整的一轮

复制代码
for i in range(3):      # 外层循环3次
    for j in range(3):  # 内层循环3次
        print(i, j)
# 总共执行 3 × 3 = 9 次

常见嵌套模式

  • 九九乘法表:i 控制行,j 控制列

  • 图形打印:外层控制行,内层控制每行的内容

  • 排列组合:多层循环生成所有可能

3. 无限循环与 break
复制代码
while True:  # 无限循环
    代码块
    if 退出条件:
        break  # 跳出循环

使用场景

  • 游戏主循环

  • 服务器程序

  • 需要一直等待用户输入

4. 字符串格式化
格式 含义 示例 输出
{:2} 宽度2,右对齐 f"{5:2}" " 5"
{:<2} 宽度2,左对齐 f"{5:<2}" "5 "
{:0>2} 宽度2,左边补0 f"{5:0>2}" "05"
{:.2f} 保留2位小数 f"{3.14159:.2f}" "3.14"

二、编程思维培养

1. 条件循环思维

核心思想:不关注"做几次",关注"什么时候停"

实际应用

  • 登录系统:一直提示输入密码,直到正确

  • 文件读取:一直读取,直到文件末尾

  • 网络请求:一直重试,直到成功或超过最大次数

2. 嵌套分解思维

核心思想:复杂问题分解为多个简单层次

以九九乘法表为例

复制代码
问题:打印九九乘法表
├── 第一层:控制行数(1-9行)
│   └── for i in range(1, 10)
├── 第二层:控制每行的列数(第i行有i列)
│   └── for j in range(1, i+1)
└── 第三层:打印每个算式
    └── print(f"{j}*{i}={i*j}", end='\t')
3. 模式识别思维

核心思想:观察规律,用数学表达式描述

图形打印通用套路

  1. 观察每行的变化规律(空格数、符号数)

  2. 用行号 i 表示规律

  3. 用循环生成每行内容


三、常见错误与避坑指南

❌ 错误1:死循环(忘记更新条件变量)
复制代码
# 错误
i = 1
while i <= 10:
    print(i)
    # 忘记写 i += 1,导致无限循环

# 正确
i = 1
while i <= 10:
    print(i)
    i += 1  # 记得更新条件变量!
❌ 错误2:循环条件永远为假
复制代码
# 错误
i = 100
while i < 10:  # 条件一开始就为假,循环体一次都不执行
    print(i)
    i += 1

# 检查:确保初始值满足循环条件
❌ 错误3:混淆 break 和 continue
复制代码
# break:跳出整个循环
for i in range(10):
    if i == 5:
        break  # 直接结束循环,不再执行后续迭代
    print(i)  # 输出 0,1,2,3,4

# continue:跳过本次循环的剩余代码
for i in range(10):
    if i == 5:
        continue  # 跳过i=5的print,继续下一次迭代
    print(i)  # 输出 0,1,2,3,4,6,7,8,9
❌ 错误4:嵌套循环的缩进错误
复制代码
# 错误:内层循环没有正确缩进
for i in range(3):
for j in range(3):  # IndentationError!
    print(i, j)

# 正确
for i in range(3):
    for j in range(3):  # 注意缩进!
        print(i, j)
❌ 错误5:字符串格式化语法错误
复制代码
# 错误
print("{:2}".format(5))  # 正确,但f-string更简洁
print(f"{5:2d}")  # 正确
print(f"{5:2f}")  # 错误!整数不能用f格式

# 正确
print(f"{5:2}")  # 整数默认格式
print(f"{5.5:2f}")  # 浮点数用f格式

四、知识延伸与拓展

1. 循环中的 else 子句

whilefor 都可以有 else,在循环正常结束 时执行(不是被 break 打断):

复制代码
for i in range(5):
    if i == 10:  # 不会执行
        break
else:
    print("循环正常结束,没有被break")  # 会执行

for i in range(5):
    if i == 3:
        break
else:
    print("循环正常结束")  # 不会执行,因为被break了

实用场景:查找元素,找不到时执行else

复制代码
target = 7
for i in range(5):
    if i == target:
        print("找到了!")
        break
else:
    print("没找到")  # target=7不在range(5)中,会执行
2. 迭代器与生成器(进阶)

range() 返回的是一个可迭代对象,不是列表(Python 3),节省内存:

复制代码
# range(1000000) 不会创建包含100万个数的列表
# 而是创建一个"按需生成"的迭代器

# 如果需要列表,可以转换
numbers = list(range(10))  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
3. 列表推导式(简化循环)

用一行代码替代简单的for循环:

复制代码
# 传统写法
squares = []
for i in range(10):
    squares.append(i ** 2)

# 列表推导式(更简洁)
squares = [i ** 2 for i in range(10)]

# 带条件的列表推导式
evens = [i for i in range(10) if i % 2 == 0]  # [0, 2, 4, 6, 8]
4. enumerate() 函数

同时获取索引和元素:

复制代码
fruits = ['苹果', '香蕉', '橙子']

# 传统写法
for i in range(len(fruits)):
    print(f"{i}: {fruits[i]}")

# 用enumerate更优雅
for i, fruit in enumerate(fruits):
    print(f"{i}: {fruit}")
# 输出:
# 0: 苹果
# 1: 香蕉
# 2: 橙子

五、下篇预告

在下一篇文档中,我们将学习:

函数(Function)

  • 什么是函数?为什么要用函数?

  • 函数的定义与调用

  • 参数与返回值

  • 变量的作用域(局部变量 vs 全局变量)

  • 默认参数、可变参数、关键字参数

  • 递归函数(函数调用自身)

  • lambda 表达式(匿名函数)

  • 内置函数速查

学习目标

  • 掌握"代码复用"的核心思想

  • 学会将复杂问题分解为多个函数

  • 能够编写结构清晰、可维护的代码

实战项目

  • 编写一个计算器程序(加减乘除函数)

  • 实现一个简易的通讯录管理系统


💡 学习建议

  1. 循环是编程的基础,一定要多练习图形打印题(金字塔、菱形等)

  2. 理解嵌套循环的执行流程,可以画图辅助理解

  3. 遇到死循环不要慌,按 Ctrl+C 可以强制终止

  4. 字符串格式化很实用,建议熟记常用的几种格式

🏆 通关挑战

选择题

1. 以下代码有什么问题?

复制代码
tag = 'y'
for tag == 'y':
    print('好好学习')
    tag = input('继续?y/n:')
  • A. 第1行改成 tag=y

  • B. 第2行 for 改成 while

  • C. 第3行改成 print("我要好好学习")

  • D. 没有错误

2. 想要输出10行10列的*,代码对吗?

复制代码
for i in range(1, 10):
    for j in range(1, 11):
        print('*', end='')
    print()
  • A. 第1行10改成11

  • B. 第2行11改成10

  • C. 第2行 range 改成 random

  • D. 正确


🔑 答案与解析

第1题:答案 B

解析过程:

  1. 首先看代码结构,第2行用的是 for tag == 'y',这是错误的语法

  2. for 循环后面应该跟可迭代对象(如 range()、列表、字符串等),而不是条件表达式

  3. 这里需要实现的是"条件为真就继续循环"的逻辑,应该用 while 循环

  4. 正确写法:while tag == 'y':

  5. 其他选项分析:

    • A选项:改成 tag=y 会把 y 当成变量,但 y 未定义,会报错

    • C选项:引号问题不是语法错误的关键

    • D选项:明显有语法错误

第2题:答案 A

解析过程:

  1. 题目要求输出10行10列,即外层循环10次,内层循环10次

  2. range(1, 10) 生成的是 1-9,只有9个数,所以只会输出9行

  3. 要输出10行,需要改成 range(1, 11)range(10)

  4. 其他选项分析:

    • B选项:内层循环11改成10,只会输出9列,不符合要求

    • C选项:random 是随机模块,不能替代 range

    • D选项:代码有错误,不能正确输出10行


编程题

1. 求10-300以内同时能被7和8整除的整数。


🔑 参考实现与解析

点击查看代码

复制代码
# 方法1:遍历判断(通用方法)
for num in range(10, 301):
    if num % 7 == 0 and num % 8 == 0:
        print(num)

# 方法2:数学优化(7和8的最小公倍数是56)
for num in range(56, 301, 56):
    if num >= 10:
        print(num)

</details>

思路解析:

  1. 理解题意:"同时能被7和8整除"意味着这个数是7和8的公倍数

  2. 方法1 :遍历10-300的每个数,用 % 判断是否整除,逻辑简单直接

  3. 方法2:利用数学知识,7和8互质,最小公倍数是 7×8=56,所以只需遍历56的倍数

  4. 效率对比:方法2只需遍历5次(56, 112, 168, 224, 280),方法1需要遍历291次

扩展思考

  • 如果求能被3、5、7同时整除的数呢?(提示:最小公倍数是105)

  • 如何用 while 循环实现这道题?

2. 打印1-100以内含有6的数。


🔑 参考实现与解析

点击查看代码

复制代码
# 方法1:字符串判断(简洁)
for num in range(1, 101):
    if '6' in str(num):
        print(num)

# 方法2:数学方法(不用字符串转换)
for num in range(1, 101):
    temp = num
    while temp > 0:
        if temp % 10 == 6:  # 个位是6
            print(num)
            break
        temp //= 10  # 去掉个位

</details>

思路解析:

  1. 方法1 :将数字转为字符串,用 '6' in str(num) 判断是否包含字符'6'

    • 优点:代码简洁,易读

    • 缺点:涉及类型转换,效率略低

  2. 方法2:用数学方法逐位检查

    • temp % 10 获取个位数

    • temp //= 10 去掉个位数(整除10)

    • 优点:纯数学运算,效率更高

    • 缺点:代码较复杂

扩展思考

  • 如何打印不含6的数?(提示:if '6' not in str(num)

  • 如何统计含有6的数的个数?

3. 用1、2、3、4能组成多少个互不相同且无重复数字的三位数?各是多少?


🔑 参考实现与解析

点击查看代码

复制代码
count = 0
for i in [1, 2, 3, 4]:      # 百位
    for j in [1, 2, 3, 4]:  # 十位
        for k in [1, 2, 3, 4]:  # 个位
            if i != j and j != k and i != k:  # 三个数字互不相同
                print(f"{i}{j}{k}")
                count += 1
print(f"共{count}个")

</details>

思路解析:

  1. 问题分析:三位数有百位、十位、个位,每个位置可以是1、2、3、4,但不能重复

  2. 算法思路:三层循环嵌套,分别代表三个位置

    • 外层循环 i:百位,有4种选择

    • 中层循环 j:十位,有4种选择

    • 内层循环 k:个位,有4种选择

  3. 去重逻辑if i != j and j != k and i != k 确保三个数字互不相同

  4. 数学验证:根据排列组合,应该是 4×3×2 = 24 个

执行流程示例

  • i=1, j=2, k=3 → 123 ✓

  • i=1, j=2, k=4 → 124 ✓

  • i=1, j=2, k=2 → 跳过(j==k,重复)

扩展思考

  • 如果数字可以重复,有多少个?(提示:4×4×4=64)

  • 如果是四位数呢?(提示:需要四层循环)

4. 打印金字塔(输入n=5)。

复制代码
    *
   ***
  *****
 *******
*********

🔑 参考实现与解析

点击查看代码

复制代码
n = int(input("输入层数:"))
for i in range(1, n + 1):
    spaces = ' ' * (n - i)      # 空格数:n-i
    stars = '*' * (2 * i - 1)   # 星号数:2*i-1
    print(spaces + stars)

</details>

思路解析:

  1. 观察规律:以n=5为例

    • 第1行:4个空格 + 1个星号

    • 第2行:3个空格 + 3个星号

    • 第3行:2个空格 + 5个星号

    • ...

    • 第i行:(n-i)个空格 + (2*i-1)个星号

  2. 核心技巧 :字符串乘法 ' ' * 4 生成 " "(4个空格)

  3. 对齐原理:先打印空格让星号右移,再打印星号

数学规律表

行号i 空格数(n-i) 星号数(2i-1) 效果
1 4 1 *
2 3 3 ***
3 2 5 *****
4 1 7 *******
5 0 9 *********

扩展思考

  • 如何打印空心金字塔?(只有边框有星号)

  • 如何打印菱形(金字塔+倒金字塔)?

5. 打印直角三角形(输入n=4)。

复制代码
*
**
***
****

🔑 参考实现与解析

点击查看代码

复制代码
n = int(input("输入层数:"))
for i in range(1, n + 1):
    print('*' * i)

</details>

思路解析:

  1. 观察规律:第i行打印i个星号

    • 第1行:1个星号

    • 第2行:2个星号

    • 第3行:3个星号

    • ...

  2. 实现技巧'\*' \* i 生成i个星号组成的字符串

  3. 简化写法:不需要内层循环,直接用字符串乘法

对比学习

  • 直角三角形:每行星号数递增(1, 2, 3, 4...)

  • 金字塔:每行星号数也是递增,但前面要加空格对齐(1, 3, 5, 7...)

扩展思考

  • 如何打印左对齐的直角三角形?(已经是左对齐了)

  • 如何打印右对齐的直角三角形?(提示:先打印空格)

6. 打印数字金字塔(输入n=4)。

复制代码
     1
    121
   12321
  1234321

🔑 参考实现与解析

点击查看代码

复制代码
 n = int(input("输入层数:"))
 for i in range(1, n + 1):
     # 打印空格
     print(' ' * (n - i), end='')
     
     # 打印递增部分:1, 12, 123, 1234
     for j in range(1, i + 1):
         print(j, end='')
     
     # 打印递减部分:无, 1, 21, 321
     for j in range(i - 1, 0, -1):
         print(j, end='')
     
     print()

</details>

思路解析:

  1. 结构分析:每行分为三部分

    • 空格部分:右对齐用,数量为 n-i

    • 递增部分:从1到i,如 1, 12, 123, 1234

    • 递减部分:从i-1到1,如 ```,``1,21,321`

  2. 关键技巧range(i - 1, 0, -1) 生成递减序列

    • start=i-1:从i-1开始

    • stop=0:到0结束(不包含0)

    • step=-1:每次减1

  3. 拼接效果:递增 + 递减 = 对称数字

执行流程(n=3时)

  • i=1:空格" " + 递增"1" + 递减"" → " 1"

  • i=2:空格" " + 递增"12" + 递减"1" → " 121"

  • i=3:空格"" + 递增"123" + 递减"21" → "12321"

扩展思考

  • 如何打印字母金字塔?如 A, ABA, ABCBA

  • 如何打印乘法金字塔?如 1, 1*2*1, 1*2*3*2*1

相关推荐
初学者,亦行者2 小时前
利用pyecharts自动化绘制漏斗图保姆级教程
python·信息可视化·数据分析
乐观勇敢坚强的老彭2 小时前
信奥C++一维数组笔记
开发语言·c++·笔记
这就是佬们吗2 小时前
Python入门⑤-异常处理、文件操作与实战项目
开发语言·数据库·python·算法·pycharm
卷无止境2 小时前
提升 Python 代码健壮性的方法大盘点
后端·python
asdzx672 小时前
Python PDF 拆分实战指南:单页拆分与按需页码范围拆分
开发语言·python·pdf
LadenKiller3 小时前
近期AI训练量化表达,解释改写检查要按顺序
人工智能·python
李昊哲小课3 小时前
咖啡工坊 · FastAPI 22 章教程合集
服务器·人工智能·python·fastapi
孬甭_3 小时前
C++ vector
开发语言·c++
卷无止境3 小时前
Python 异常处理:从入门到工程实践
后端·python