前两节写的程序都是"从上往下一条道走到黑"。本节给程序装上"判断力"和"耐力"——让它能根据条件选路(if)、能重复干活(while / for)。
本节还有一件 Python 特有的大事:第一次正式使用缩进。在 Python 里,缩进不是"排版好看",它是语法的骨架——程序的从属关系全靠它表达。
6-1 说过 Python 用缩进代替大括号;6-3 用过判断(temp > 20 and temp < 30,结果是 True / False)。
本节把这两样拼起来:if 后面接的就是 6-3 那种"能算出真假"的表达式;而"哪几行属于这个 if",靠缩进表示。
读法建议:本节所有例子都建议在交互模式里敲,但有一个例外——多行结构(if、for、while)在交互模式里要连着敲(Python 会用 ... 提示你"接着说")。觉得别扭就直接写 .py 文件,那种手感更像正经开发。
一、程序的三种基本结构
所有程序(不夸张,是所有)都由三种结构拼出来:
| 结构 | 干什么 | 打比方 | Python 里靠什么 |
|---|---|---|---|
| 顺序 | 一条接一条往下走 | 按清单买菜 | 默认就是(你什么都不用做) |
| 分支 | 满足条件才做,否则走另一条 | 下雨就打伞 | if / elif / else |
| 循环 | 重复做,直到该停 | 绕操场跑十圈 | while / for |
顺序结构你已经会了(前两节的代码全是)。本节讲后两种。
二、缩进:Python 的"隐形大括号"
这是 Python 最独特、也最容易踩的地方。必须先讲清它,后面才讲得下去。
在 C++ 里,一段代码用 { } 圈起来:
if (5 > 3) {
printf("这是 if 里面的\n");
}
printf("这句一定执行\n");
在 Python 里,没有大括号,靠缩进表示"这几行属于这个 if":
if 5 > 3:
print("这是 if 里面的")
print("这句一定执行")
两条硬规矩:
- 冒号
:不能忘——if 条件:后面那个冒号,是"下面是属于我的代码"的信号。 - 属于它的行必须缩进——Python 社区统一用 4 个空格。
① 该缩进没缩进:
if 5 > 3:
print("坏了") # ❌ IndentationError: expected an indented block
② 缩进量不一致(同一层里有的 4 格有的 2 格):
if 5 > 3:
print("A")
print("B") # ❌ IndentationError: unindent does not match
③ Tab 和空格混用:
# 肉眼看着对齐,其实一个是 Tab 一个是 4 个空格
# ❌ TabError: inconsistent use of tabs and spaces in indentation
第 ③ 种最阴——肉眼看不出差别,只能靠报错信息。解法:用编辑器(Thonny 会自动统一),别手打。
2.1 缩进决定了"谁属于谁"——看一个真实的坑
a = 50
if a > 0:
print("是正数")
if a > 100:
print("而且很大")
else:
print("不是正数")
这个 else 对应的是哪个 if?答案:外层那个 if a > 0:——因为 else 和它缩进一样齐。
再看一个改坏的版本:
a = 50
if a > 0:
print("是正数")
if a > 100:
print("而且很大")
else:
print("但不到 100") # 这个 else 对的是内层 if
只把 else 往里挪了 4 格,意思就完全变了。 这就是"缩进即语法"的分量——在 C++ 里,你怎么排版都不影响程序;在 Python 里,挪一格就是改逻辑。
写 if / for / while 的时候,先敲冒号、回车,让编辑器自动缩进好那 4 格,再写内容。
手动"先写内容再补缩进"是缩进错误的头号来源。
三、分支:if / elif / else
3.1 三种形态
形态一:只有 if(满足就做,不满足就跳过)
temp = 35
if temp > 30:
print("太热了")
形态二:if + else(两条路选一条)
temp = 35
if temp > 30:
print("太热了")
else:
print("还好")
形态三:if + elif + else(多条路选一条)
score = 78
if score >= 90:
print("优秀")
elif score >= 60:
print("及格")
else:
print("不及格")
输出:及格
C++ / Java 里写 else if,Python 里必须合成一个词 elif(else if 的缩写)。
写成 else if 会直接语法错误。这是从 C 系语言过来最常打错的一处。
3.2 判断顺序很重要:从上往下,命中就走
elif 是"前面都没中,才轮到我"。所以条件和顺序密切相关:
score = 95
# 顺序对了
if score >= 90:
print("优秀") # → 输出这个,后面的 elif 不再看
elif score >= 60:
print("及格")
# 顺序写反了(把 >= 60 放前面)
if score >= 60:
print("及格") # → 95 也进了这条,输出"及格",错的!
elif score >= 90:
print("优秀") # 永远不会执行到
记住一句话:范围大的条件往下放、范围小的往上放。
3.3 if 后面接的"不一定是比较"
Python 会把 if 后面的东西自动转成真假(就是 6-3 学的 bool()):
name = input("你叫什么?")
if name: # 等价于 if name != ""
print(f"你好,{name}")
else:
print("你什么都没输入")
这种写法非常常见——判断"有没有内容""列表空不空""有没有拿到值",一律直接写 if 变量:。
假:False、0、0.0、""(空字符串)、[](空列表)、None
真:其他一切,包括 "0"(非空字符串)和 "False"(一段文字)
所以显示"是否成功"的结果时千万不能直接把字符串拿去做判断——它的内容是 "False" 也是"真"。
四、循环:while 与 for
4.1 while:不知道做几次,只知道"什么时候停"
count = 0
while count < 5:
print(f"第 {count + 1} 次")
count += 1
print("循环结束")
输出:
第 1 次
第 2 次
第 3 次
第 4 次
第 5 次
循环结束
while 的三个零件(缺一个就出事):
| 零件 | 作用 | 少它会怎样 |
|---|---|---|
初始值(count = 0) |
从哪儿开始 | 报 NameError |
条件(count < 5) |
什么时候继续 | 语法错误 |
改变量(count += 1) |
让条件最终会假 | 死循环! |
count = 0
while count < 5:
print("永远停不下来") # count 一直是 0,条件永远为真
程序会一直打印下去,直到你按 Ctrl + C 强行打断。
Ctrl + C 是你在树莓派上最该记住的救命键(3-5 讲过:它发的是"中断信号")。
注意:死循环会让 CPU 满转、树莓派发热,不是"无害的卡住"——发现了赶紧 Ctrl + C。
4.2 for:把"一串东西"挨个过一遍
这里有个和 C++ / Java 完全不同的地方,先说清楚:
C++ 的 for (int i = 0; i < 5; i++) 是让你自己管计数器:设初值、判断、加一,三件事都你写。
Python 的 for 是"把这个串里的每个东西,挨个拿出来用一次"——叫遍历(iterate)。
它不管数字,它管的是"一串东西"(一串数字、一串字符、一串数据都行)。
for i in range(5):
print(i)
输出:
0
1
2
3
4
注意两件事:
1. 从 0 开始(不是 1)——这是所有编程语言的惯例,因为"偏移量"从 0 数最方便。
2. range(5) 给出 0、1、2、3、4 共五个数——不含 5。这叫"左闭右开"。
range() 的三种写法:
| 写法 | 给出 | 个数 |
|---|---|---|
range(5) |
0 1 2 3 4 |
5 个 |
range(2, 5) |
2 3 4 |
3 个(含头不含尾) |
range(1, 10, 2) |
1 3 5 7 9 |
5 个(第三个参数是步长) |
因为这样 range(a, b) 的个数正好是 b - a(range(2, 5) 就是 3 个),不用 ±1 地算,很省脑子。
但代价是——想数到 10 必须写 range(1, 11)。这是新手最常数的错一格的地方。
for 不只能遍历数字——字符串也行:
for ch in "Pi":
print(ch)
输出:P 然后 i(每个字符一个)。这个能力后面用到极多(6-6 会展开)。
4.3 break 和 continue:提前跳出去 / 跳过这一轮
for i in range(1, 11):
if i == 4:
continue # 跳过 4,继续下一轮
if i == 8:
break # 到 8 就直接结束整个循环
print(i)
输出:1 2 3 5 6 7
| 关键字 | 作用 | 打比方 |
|---|---|---|
break |
结束整个循环 | 找到想要的就收工 |
continue |
跳过这一轮剩下的,直接进下一轮 | 这个不要,看下一个 |
4.4 while True + break:最常用的写法
想让用户"反复输入,直到他输对为止",但你事先不知道要几轮——标准写法是:
while True:
answer = input("请输入 yes 或 no:")
if answer == "yes":
print("好的,继续。")
break # ← 唯一的出口
elif answer == "no":
print("那就算了。")
break
else:
print("只认 yes 或 no,再来一次。")
这不是"死循环写错了",而是故意写的"无限循环 + 出口"。 那些"输错就重来"的程序全是这个套路——本节的 Demo 就是它。
五、动手 Demo:猜数字游戏
把本节的判断和循环全用上。在命令行里写:
cd ~/projects
nano guess.py
内容:
import random # 下一节会正式讲"模块",这里先用
secret = random.randint(1, 100) # 随机想一个 1~100 的整数
tries = 0 # 记次数
print("我想了一个 1 到 100 之间的整数,你来猜。")
while True: # 一直循环,直到猜对才 break 出去
guess = int(input("请输入你的猜测:"))
tries += 1
if guess < secret:
print("小了,再大一点。")
elif guess > secret:
print("大了,再小一点。")
else:
print(f"猜对了!答案就是 {secret},你一共猜了 {tries} 次。")
break
跑:
python3 guess.py
看到什么算成功(每次运行的数字都不一样,因为答案是随机的。下面是一次真实过程的示例):
我想了一个 1 到 100 之间的整数,你来猜。
请输入你的猜测:50
小了,再大一点。
请输入你的猜测:75
大了,再小一点。
请输入你的猜测:63
小了,再大一点。
请输入你的猜测:69
猜对了!答案就是 69,你一共猜了 4 次。
读结果:
| 你输入 | 程序判断 | 为什么 |
|---|---|---|
50 |
小了 | 50 < 69 → 走第一个 if |
75 |
大了 | 75 > 69 → 第一个 if 不中、elif 中 |
63 |
小了 | 又进第一个 if |
69 |
对了 | 前面都不中 → 进 else,打印后 break 退出循环 |
这个程序里有本节全部的知识点:
| 代码 | 用到的知识 |
|---|---|
while True: |
无限循环 |
if / elif / else |
三分支判断(顺序很关键) |
break |
唯一出口 |
tries += 1 |
增强赋值(6-3) |
f"...{secret}..." |
f-string(6-3) |
int(input(...)) |
输入是字符串,要转(6-3) |
① 把 random.randint(1, 100) 改成 random.randint(1, 10) —— 猜的次数会明显变少。
② 故意输入一个字母(比如 abc)——程序会崩,报 ValueError。这不是你写错了,而是"用户输入不可信"这个真问题——后面讲异常处理时会正式解决它(先在 6-2 学的报错读法里确认一下:是不是 line N 指出了 int(...) 那一行)。
六、30 秒实验
实验一:亲手制造一次 IndentationError
nano indent_test.py
写入(print 故意不缩进):
if 5 > 3:
print("坏了")
跑 python3 indent_test.py,会看到:
File "/home/你的用户名/projects/indent_test.py", line 2
print("坏了")
^
IndentationError: expected an indented block after 'if' statement on line 1
认识这个报错名——IndentationError,Python 独有的错误类型。以后看到它,第一反应就是"缩进"。
实验二:乘法表(两层循环,练嵌套)
for i in range(1, 5):
for j in range(1, i + 1):
print(f"{j}x{i}={i * j}", end=" ") # end=" " 表示"别换行,用两个空格隔开"
print() # 空的 print() 就是"换一行"
输出:
1x1=1
1x2=2 2x2=4
1x3=3 2x3=6 3x3=9
1x4=4 2x4=8 3x4=12 4x4=16
读法(验证第一行和最后一行):
- 外循环 i=1:内循环 range(1, 2) 只给 j=1 → 输出 1x1=1 ✅
- 外循环 i=4:内循环 range(1, 5) 给 j=1,2,3,4 → 依次输出 1x4=4、2x4=8、3x4=12、4x4=16 ✅
- 每次外循环结束,那个空的 print() 负责换行 —— 这就是它为什么是一行一行长的三角形。
end=" " 是什么:print() 默认结束时会自动换行;加 end="..." 就改成"用指定的东西结尾",这里用两个空格,所以同一行的几个算式能挤在一起。
实验三:range 的三种写法,亲手对一遍
>>> list(range(5))
[0, 1, 2, 3, 4]
>>> list(range(2, 5))
[2, 3, 4]
>>> list(range(1, 10, 2))
[1, 3, 5, 7, 9]
>>> len(list(range(2, 5)))
3
(list(...) 是"把一串东西显示出来"的办法,len(...) 是数个数——这两个下一节 6-5 / 6-6 会正式讲。)
七、常见误区
- "缩进随便,别歪就行" —— 缩进是语法,而且挪一格就改逻辑(2.1 那个
else的例子)。同一层统一 4 个空格,别混 Tab。 - "
else if分开写" —— Python 里必须合起来写elif。写else if直接语法错误。 - "
for i in range(5)会数到 5" —— 数到 4。range是"含头不含尾"。想数到 5 要写range(1, 6)。 - "循环里改
i能让它多跑几轮" —— 不行。Python 的for每一轮都会重新从序列里取下一个值,你在循环体里改i是白改:python for i in range(3): i = 100 # 没用,下一轮 i 又变成 1 print(i) # 输出 100 100 100(这一点和 C 的for很不同,想控制进度请用while。) - "死循环无所谓,反正卡住而已" —— CPU 会满转、树莓派会发烫(本课后面要讲散热)。发现卡住了:
Ctrl+C。 - "
while 条件:里的条件只在开始时判断一次" —— 每一轮都判断。所以循环体里必须有一个能改变它的动作,否则永远出不去。 - "字符串
"False"是假的" —— 它非空,所以是真。if "False":会执行!只有False(布尔值本身)、0、""、None这些才是假的。
自测三问(点开对答案)
1. Python 里"哪几行属于这个 `if`"靠什么表示?和 C++ 有什么不同? 2. `range(1, 6)` 会给出哪些数字?一共几个? 3. `break` 和 `continue` 有什么不同? **参考答案** 1. **靠缩进**(同一层统一 4 个空格)。**C++ 用大括号 `{ }` 圈起来,缩进怎么乱放都不影响程序**;Python 里**缩进就是语法本身**——而且它决定的正是"从属关系",所以把 `else` 挪一格,`else` 或许就配给另一个 `if` 了,**逻辑会静默地变掉**。 2. **`1 2 3 4 5`,一共 5 个**。`range(a, b)` 是**含头不含尾**:从 1 开始、到 6 之前停,所以真给出的是 1 到 5。好处是**个数正好等于 `b - a`(6−1=5)**,不用 ±1 地算。 3. **`break` 结束整个循环**("找到就走人");**`continue` 只跳过这一轮剩下的部分,接着跑下一轮**("这个不要,看下一个")。- ☐ 下一节(6-5 Python 函数与模块)
相关笔记
- Python 变量与运算符 —— 上一节:
if后面接的"真假判断"就是那里学的比较与逻辑运算符 - 在 Raspberry Pi OS 执行命令 ——
Ctrl+C强行打断死循环,就是那里学的"中断信号" - 判断语句 —— C++ 用大括号圈代码块的对照;
switch也是那里学的 - for循环语句 —— 计数式 for 的对照:C 的 for 让你管计数器,Python 的 for 是"遍历一串东西"
- 🍓 树莓派 · 索引 —— 全课路线图