第 3 课 流程控制

3.1 布尔值与比较运算

程序要做判断,判断的结果只有两种:True(真)和 False(假)。

>>> 3 > 2
True
>>> 3 > 5
False

六个比较运算符:

运算符 含义 例子 结果
== 等于 3 == 3 True
!= 不等于 3 != 3 False
> 大于 3 > 2 True
< 小于 3 < 2 False
>= 大于等于 3 >= 3 True
<= 小于等于 3 <= 2 False

⚠️ 最高频错误:把 ==(比较)写成 =(赋值)。if x = 3: 会直接报 SyntaxError,这也算好事——至少它不会默默做错事。

Python 支持链式比较,可以直接写数学里的区间:

>>> 1 < 2 < 3
True
>>> 1 < 3 < 2
False        # 等价于 1 < 3 and 3 < 2
>>> age = 25
>>> 18 <= age < 60
True

3.2 逻辑运算:and、or、not

>>> True and False
False
>>> True or False
True
>>> not True
False

真值表:

A B A and B A or B
True True True True
True False False True
False True False True
False False False False

and 要求两边都真,or 只要一边真,not 取反。

把条件翻译成代码

age = 25
has_ticket = True

# 「年龄满 18 且持有门票」
if age >= 18 and has_ticket:
    print("可以入场")

# 「年龄不满 18,或者没有门票」
if age < 18 or not has_ticket:
    print("不能入场")

短路求值

and 和 or 不一定会看完右边——结果已经确定时立刻停止。这既是性能优化,也是防错手段:

x = 0

# 先判断 x != 0,为 False 时右边的除法不会执行,避免除以 0 崩溃
if x != 0 and 10 / x > 1:
    print("成立")
else:
    print("不成立")      # 输出:不成立

name = input("名字:") or "匿名用户"    # 输入为空时用默认值

上面这行利用了「or 返回第一个为真的操作数」,是 Python 里很常见的写法。不过对初学者来说,写成 if not name: name = "匿名用户" 更直白。

and / or 的返回值不一定是布尔值

>>> 0 and "hello"
0
>>> 3 and "hello"
'hello'
>>> "" or "默认"
'默认'

and 返回第一个假值(全真则返回最后一个),or 返回第一个真值(全假则返回最后一个)。知道这个规则,上面 or "匿名用户" 的写法就说得通了。

3.3 if / elif / else

score = 85

if score >= 90:
    print("优秀")
elif score >= 75:
    print("良好")
elif score >= 60:
    print("及格")
else:
    print("不及格")

输出:

良好

三条规则必须记住:

  1. 每个条件后面有冒号 :,这是很多新手第一个 SyntaxError。

  2. 代码块靠缩进划分,通常是 4 个空格。同一块内缩进必须一致。

  3. 从上往下依次判断,命中一个就跳出整个结构,后面即使条件也成立也不会执行。

    x = 100 if x > 0: print(“正数”) elif x > 50: # 永远不会执行到,因为 x > 0 已经命中了 print(“大于 50”)

所以 elif 的顺序很重要:范围判断要从窄到宽,或者从宽到窄统一排列,别让宽条件把窄条件吃掉。

嵌套 if

if age >= 18:
    if has_ticket:
        print("入场")
    else:
        print("先买票")
else:
    print("未成年")

嵌套超过两层就该考虑重构(用 and 合并条件、提前 return、拆函数)。平铺的代码永远比嵌套的好读。

空代码块用 pass 占位

if score >= 60:
    pass          # 还没想好写什么,先占位,否则 IndentationError
else:
    print("补考")

3.4 直接判断「真假」

if 后面不一定非得是比较表达式,任何值都能判断真假:

items = []

if items:                 # 空列表为假
    print("有内容")
else:
    print("空列表")        # 输出这个

name = ""
if not name:
    print("名字为空")

Python 的假值只有这几个:False、None、0、0.0、""、[]、()、{}、set()。其它都是真。

所以下面两种写法等价,但第一种更地道:

if items:                 # ✅ 推荐
if len(items) > 0:        # 😐 能用,但啰嗦

判断 None 时用 is,不要用 ==:

if result is None:
    print("没有结果")

is 比较的是「是不是同一个对象」,None 全局只有一个,所以 is None 既准确又更快。

3.5 三元表达式

只有「二选一」时,可以写成一行:

age = 20
status = "成年" if age >= 18 else "未成年"
print(status)      # 成年

结构是 值A if 条件 else 值B。读起来像英文:「A,如果条件成立,否则 B」。

不要嵌套三层以上,那种时候老老实实写 if。

3.6 while 循环:条件为真就一直做

count = 1
while count <= 5:
    print(count)
    count += 1        # 千万别忘这行

输出 1 2 3 4 5,每个一行。

while 的逻辑:检查条件 → 为真则执行循环体 → 回到检查条件 → ……直到条件为假。

死循环与如何避免

# ❌ 死循环:count 永远不变,条件永远为真
count = 1
while count <= 5:
    print(count)

按 Ctrl + C 可以强制中断。写 while 时养成习惯,先问自己两个问题:

  1. 哪个变量控制循环结束?
  2. 它在循环体里真的被改变了吗?

while True + break:菜单式程序的标准写法

while True:
    cmd = input("输入命令(q 退出):")
    if cmd == "q":
        break
    print(f"你输入了:{cmd}")

print("程序结束")

这种「不知道要循环多少次,靠条件退出」的场景,用 while True + break 最清晰。

累加与计数模板

total = 0
i = 1
while i <= 100:
    total += i
    i += 1
print(total)      # 5050

「初始化累加器 → 循环里更新 → 循环外使用」是所有统计类代码的骨架。

3.7 for 循环:遍历一个序列

for 用来「把一堆东西挨个处理一遍」:

for ch in "Python":
    print(ch)

输出 P y t h o n。

fruits = ["苹果", "香蕉", "橘子"]
for fruit in fruits:
    print(f"我喜欢吃{fruit}")

比 while 省事:不需要索引、不需要手动加一、不会越界。能用 for 就别用 while。

range():生成一串整数

range(5)          # 0 1 2 3 4        左闭右开,不含 5
range(1, 5)       # 1 2 3 4
range(0, 10, 2)   # 0 2 4 6 8        步长 2
range(5, 0, -1)   # 5 4 3 2 1        倒着数

for i in range(1, 6):
    print(i, end=" ")      # 1 2 3 4 5

⚠️ off-by-one 错误:range(1, 5) 不含 5。要「1 到 5」必须写 range(1, 6)。这是全世界程序员都犯过的错,写循环时念一遍「左闭右开」。

需要下标时用 enumerate

names = ["小明", "小红", "小刚"]
for i, name in enumerate(names, start=1):
    print(f"{i}. {name}")

输出:

1. 小明
2. 小红
3. 小刚

别写 for i in range(len(names)),再用 names[i] 取值——啰嗦且容易越界。

3.8 break、continue 和循环的 else

关键字 作用
break 立刻跳出当前整个循环
continue 跳过本轮剩余代码,直接进入下一轮
pass 什么也不做,纯占位
# break:找到就停
for n in range(2, 100):
    if n % 7 == 0:
        print(f"第一个能被 7 整除的数是 {n}")
        break

# continue:跳过偶数
for i in range(1, 11):
    if i % 2 == 0:
        continue
    print(i, end=" ")      # 1 3 5 7 9

for ... else 是个冷门但好用的语法:循环正常跑完(没被 break)时执行 else。

target = 17
for n in range(2, int(target ** 0.5) + 1):
    if target % n == 0:
        print(f"{target} 不是质数")
        break
else:
    print(f"{target} 是质数")

如果觉得 else 容易误解,可以改用标志变量,效果一样,只是多两行。

3.9 嵌套循环

外层跑一次,内层跑一整轮:

for i in range(1, 4):
    for j in range(1, 4):
        print(f"({i},{j})", end=" ")
    print()      # 每行结束换行

输出:

(1,1) (1,2) (1,3)
(2,1) (2,2) (2,3)
(3,1) (3,2) (3,3)

经典练习:九九乘法表

for i in range(1, 10):
    for j in range(1, i + 1):        # 内层只跑到 i,形成三角
        print(f"{j}×{i}={i * j}", end="\t")
    print()

输出前两行:

1×1=1
1×2=2    2×2=4

\t 是制表符,用来对齐列。如果中文列宽对不齐,可以改用 f-string 的宽度控制 f"{...:<8}"。

嵌套循环里的 break 只跳一层

for i in range(3):
    for j in range(3):
        if j == 1:
            break          # 只跳出内层,外层继续
        print(i, j)

输出 0 0、1 0、2 0。要一次跳出两层,常见做法是加标志位或用函数 return(第 5 课)。

3.10 常见坑清单

现象 原因 修法
SyntaxError: expected ':' if/for/while 后面漏冒号 补 :
IndentationError 缩进不一致,Tab 和空格混用 统一 4 空格
程序卡住不动 while 条件永远为真 检查控制变量是否更新
循环少跑/多跑一次 range 左闭右开 终点写「实际值 + 1」
条件永远不成立 用了 = 而不是 ==,或类型不匹配("18" == 18 为 False) 检查运算符和类型
判断浮点数相等失败 0.1 + 0.2 == 0.3 为 False 用 round 或误差范围

另外两个隐蔽的坑:

# 坑一:字符串和数字比较,Python 3 直接报错,别指望它「自动转换」
>>> "18" > 9
TypeError: '>' not supported between instances of 'str' and 'int'

# 坑二:浮点数做循环条件,可能永远差一点点
>>> i = 0.0
>>> while i != 1.0:      # 危险!0.1 累加十次不等于 1.0
...     i += 0.1

浮点数循环改用整数计数:

for k in range(10):
    i = k / 10

3.11 小结

  • 比较得到布尔值,== 是比较,= 是赋值
  • and / or 短路求值,可以拿来防除零、设默认值
  • if / elif / else 从上往下命中即止,缩进决定归属
  • 假值:False、None、0、""、[]、{}
  • 次数已知用 for,条件驱动用 while
  • range 左闭右开;要下标用 enumerate
  • break 跳一层,continue 跳一轮
  • 嵌套循环内层跑满,外层才走一步

3.12 课后练习

练习 1 输入一个整数,判断它是正数、负数还是零。

练习 2 输入年份,判断是否闰年。规则:能被 4 整除但不能被 100 整除,或者能被 400 整除。

练习 3 打印 1~100 中所有能被 3 或 5 整除的数,每行 5 个。

练习 4 FizzBuzz:1~100,能被 3 整除打印 Fizz,能被 5 整除打印 Buzz,能同时被 3 和 5 整除打印 FizzBuzz,其余打印数字本身。

练习 5 猜数字游戏:程序随机想一个 1~100 的数,用户反复猜,程序提示「大了」或「小了」,猜对时输出猜了几次。

练习 6 打印如下图形(高度由用户输入,这里以 4 为例):

*
**
***
****

参考答案

练习 1

num = float(input("输入一个数:"))
if num > 0:
    print("正数")
elif num < 0:
    print("负数")
else:
    print("零")

练习 2

year = int(input("年份:"))
if (year % 4 == 0 and year % 100 != 0) or year % 400 == 0:
    print(f"{year} 是闰年")
else:
    print(f"{year} 是平年")

括号很关键。and 的优先级高于 or,不加括号时结果其实一样,但加上括号能让读代码的人立刻看懂逻辑分组。

练习 3

count = 0
for i in range(1, 101):
    if i % 3 == 0 or i % 5 == 0:
        print(f"{i:>4}", end="")
        count += 1
        if count % 5 == 0:
            print()          # 每 5 个换一行

练习 4

for i in range(1, 101):
    if i % 15 == 0:
        print("FizzBuzz")
    elif i % 3 == 0:
        print("Fizz")
    elif i % 5 == 0:
        print("Buzz")
    else:
        print(i)

顺序不能反:如果先判断 i % 3 == 0,那 15 的倍数会先命中 Fizz,永远输出不到 FizzBuzz。这是「条件顺序决定结果」的典型案例。

练习 5

import random          # import 的用法第 7 课细讲,这里照抄即可

target = random.randint(1, 100)
count = 0

while True:
    guess = int(input("猜一个 1-100 的数:"))
    count += 1
    if guess < target:
        print("小了")
    elif guess > target:
        print("大了")
    else:
        print(f"猜对了!你用了 {count} 次")
        break

练习 6

n = int(input("高度:"))
for i in range(1, n + 1):
    print("*" * i)

"*" * 3 得到 "***",字符串乘法是打印图形最省事的工具。想打印居中的金字塔,改成:

for i in range(1, n + 1):
    print(" " * (n - i) + "*" * (2 * i - 1))

评论

评论区即 对应 issue 的讨论串,登录 GitHub 即可留言。