price = 98
if price < 100:
print('buy')buy
我们的程序到目前为止大多是“一条道走到黑”,从上到下顺序执行每一行代码。
完成本章学习后,你将能够:
if, elif, else 语句,让你的程序根据特定条件执行不同的代码路径,实现决策逻辑。while 循环,在满足特定条件时重复执行一段代码。for 循环,遍历序列(如列表、字符串、元组)或其他可迭代对象中的每一个元素,并对它们进行操作。range() 函数如何与 for 循环结合,方便地执行固定次数的重复任务。break 和 continue 语句来更精细地控制循环的流程。掌握了条件和循环,你的程序将不再是简单的线性执行,而是能够根据输入和中间结果展现出“智能”行为,能够自动化处理大量重复工作。这是从编写简单脚本到构建复杂应用程序的关键一步。
注意:Tab键原本用于输入“制表符 ,但是在VS Code中,这个按键的默认行为是用空格来补全缩进。
(推荐) 使用 VS Code 的插件 indent-rainbow (或者类似的其他插件),可以用不同颜色显示缩进的层级。建议在 VS Code 设置中开启“Insert Spaces: true, Tab Size: 4”。忘记怎么安装或设置的可以看前面的章节。
if 语句:

price = 98
if price < 100:
print('buy')buy
if-else语句:

price = 102
if price < 100:
print('buy')
else:
print('not buy')not buy
if-elif语句:

price = 102
if price < 100:
print('buy')
elif price < 110:
print('hold')
elif price < 120:
print('think about it')
else:
print('sell')hold
price = 70
if price < 80: print('buy')buy
小提示:实际项目中更推荐使用多行 if,可读性更好。
price = 85
decision = "buy" if (price < 80) else "don't buy"
print(decision)don't buy
练习1:小明身高1.75m,体重80.5kg。请根据BMI公式(体重除以身高的平方)帮小明计算他的BMI指数,并根据BMI指数:
用if-elif判断并打印结果:
小提示:
height = 1.75
weight = 80.5
# 计算BMI指数
# 用 if-elif 判断,并打印结果
# 提示:可以使用链式比较,比如 18.5 <= bmi < 25练习2:判断闰年:从year, 判断是否为闰年?
提示1: 闰年: 年份能被4整除但不能被100整除的 或者 能被400整除
提示2: 判断一个数字能否被某个数整除,可以判断其余数(取余运算是%)是否为0,如a % 2 == 0如果为True则为偶数。
注:可以用多层的条件语句,或者用多个逻辑运算来写。
year = 2005 # 或者任何一年例子:用if-else求a、b、c 3个数中最大的一个
思路:
a = 4
b = 9
c = 2
if a>b:
if a>c:
max_value=a
else:
max_value=c
else:
if b>c:
max_value=b
else:
max_value=c
print(f"最大值是{max_value}") 最大值是9
对一个变量number,判断是否能被2或者3整除
按具体的情况,请输出:
你输入的数字可以整除 2 和 3
你输入的数字可以整除 2,但不能整除 3
你输入的数字可以整除 3,但不能整除 2
你输入的数字不能整除 2 和 3
思路:
前面讲过,布尔型有2种,真True和假False。
实际上,这2个符号,是布尔型变量的值,和1,2,3,4是整型的值,'apple'是字符串的值类似。但布尔型的值只有2种。
例如,有一个变量,用于表示“现在是否下雨”。这个问题只有2个答案,是或者否,显然这就可以用布尔型来表示:True就表示下雨,False就表示没下雨。我们就定义一个布尔型变量is_raining。
注意:为了达到顾名思义的效果,布尔型的变量,可以考虑用is_,has_等等开头,显示这是个“是否”问题的答案。
# 表示现在正在刮风下雨
is_raining = True
is_windy = True判断是否同时在刮风和下雨
print(is_raining and is_windy)True
布尔运算,其结果,也是一个布尔类型的变量:因此可以赋值给另一个变量。
bad_weather = is_raining and is_windy # 布尔运算的结果,也是一个布尔型,并且可以赋值给另一个变量
print(bad_weather)True
换一种理解,你可以把and运算,看成一个函数。类似于:
bool_and(x, y)
就可以视为一个函数调用,返回的结果,就是与操作
bad_weather = bool_and(is_raining, is_windy) # 这是随便写的,无法执行回到我们的if语句。if语句接受的判断条件,本质上一个布尔型变量
if is_raining and is_windy:
print("don't go outside!")don't go outside!
等价于:
if bad_weather:
print("don't go outside!")don't go outside!
所以,你在if后面跟一个布尔型变量bad_weather,或者一个条件is_raining and is_windy,是等价的。但后者可以少进行一次赋值的操作,并且节约一个变量名。
回看前面的例子:
a = 2
b = 3
if a > b:
print('a > b')
else:
print('a <= b')a <= b
可以把a > b看成是“一个布尔型的变量”,这个变量,保存了a > b的结果,只是我们没有把这个结果赋值给一个变量名(没有绑定一个标签),而是直接放进了if语句中。
这等价于:
a = 2
b = 3
is_a_bigger = a > b
if is_a_bigger:
print('a > b')
else:
print('a <= b')a <= b
小结,布尔运算,实际上会返回一个新的布尔值,可以和任何变量一样进行操作,比如绑定名字,放进if里等等
在 Python 中,and 与 or 具有短路特性:
A and B: 当 A 为假(False)时,B 不再计算;当 A 为真时才计算 B。A or B: 当 A 为真(True)时,B 不再计算;当 A 为假时才计算 B。另外,很多对象在布尔上下文中有“真/假”语义:空字符串 ""、空列表 []、空字典 {}、数字 0、以及 None 都被视为“假”,其余通常为“真”。
print(bool(""), bool("hi")) # False True
print(bool([]), bool([1])) # False True
print("a" and "b") # 'b'
print("" or "fallback") # 'fallback'False True
False True
b
fallback
not > and > or。复杂表达式建议加括号以增强可读性。x in s / x not in s,适用于字符串、列表、字典(测试键)。is / is not 判断“是否是同一对象”,不是数值相等判断;比较值请用 ==。0 <= x < 10,等价于 0 <= x and x < 10,更可读。any(iterable) 有任一真即真;all(iterable) 全真才真。print(not False and True)
print('a' in 'cat') # True
print(0 <= 5 < 10) # True
print(any([0, '', 3])) # True(3 为真)
print(all([1, 2, 0])) # False(0 为假)True
True
True
True
False
while循环比较直观,只要条件成立,就重复执行某块代码块
或者说,重复执行某块代码块,直到条件不成立为止
while 判断条件(condition):
执行语句(statements)
思想:
+=例如 i += 2即让i自增2,等价于 i = i + 2
i = 1
i += 2
print(i)3
设计一个从1到10的循环
i = 1
while i <= 10:
print(i)
i += 1
print("循环结束")1
2
3
4
5
6
7
8
9
10
循环结束
小提示:如何判断一个数是否是偶数?取余的操作符是%
小提示:你可以建立一个新的变量,用来存放累加的结果。
for循环一般用于遍历一个可迭代对象(如列表 List、元组 Tuple、字典 Dict、字符串、range 等)
其作用是“对其中的每一个元素都做点什么”。
如果你要对一个List中的每一个元素都做点什么,此时就应该用for循环。
例如,我们要打印a = [1,2,3,4,5]中的每一个元素
或者说,我们要对a = [1,2,3,4,5]中的每一个元素,执行打印这个动作。
a_list = [1,2,3,4,5]
for i in a_list:
print(i)1
2
3
4
5
解释
a = [1,2,3,4,5]中的每一个元素,执行打印这个动作。a_list是一个列表的名字for i in a_list::我们把中的每一个元素,按顺序,逐个过一遍。轮到哪个元素,我们就用i来指向它。print(i):由上一句,i可以看作每一个元素代称,我们打印它。注意,前面有“1个缩进”。range(起点, 终点, 步长):快速生成一个序列:惰性的(lazy)可迭代序列
range(0,10):生成一个0 ~ 9的自然数序列(包括起点,不包括终点)range(0,10,2):生成一个0 ~ 8的偶数序列(包括起点,不包括终点)print(range(0, 10))
print(list(range(0, 10))) range(0, 10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
在for循环中,我们往往用range来快速生成一个数字序列,避免手动输入非常多的数字。
print('打印奇数序列:')
for i in range(1, 20, 2): # 替代手动输入 [1,3,5 ...]
print(i)打印奇数序列:
1
3
5
7
9
11
13
15
17
19
注意:遍历时不要原地修改同一个列表的元素数量,否则可能“跳项”或结果异常;可以使用列表推导式构造新列表,或遍历副本。
xs = [1, 2, 3, 4]
for x in xs:
if x % 2 == 0:
xs.remove(x) # 反例:修改正在遍历的列表
# 推荐做法 1:列表推导式
xs = [1, 2, 3, 4]
xs = [x for x in xs if x % 2 != 0]
# 推荐做法 2:遍历副本
xs = [1, 2, 3, 4]
for x in xs[:]:
if x % 2 == 0:
xs.remove(x)range(5),起点默认为 0,步长为 1。range(10, 0, -1) 生成 10, 9, ..., 1。我们就可以:
注意: break和continue,在for和while循环中都可以使用。
# break 的范例
# for语句试图执行1000次循环
# 但中途被break语句中断
for i in range(1000):
print(i)
if i >= 3:
print('如果i大于等于3,则中断循环。')
break
print('循环结束')0
1
2
3
如果i大于等于3,则中断循环。
循环结束
# continue 的范例
# 每次遇到偶数,就会直接开始下一次迭代
# 因此i为偶数时,print将不会被执行
# 只打印列表中的奇数
numbers = [1, 2, 3, 4, 5, 6]
for num in numbers:
if num % 2 == 0: # 如果是偶数
continue # 跳过本次循环中后续的print语句,直接开始下一次迭代
print(num) # 这行只在num是奇数时执行1
3
5
当循环“正常结束”(即不是通过 break 提前跳出)时,会执行与之配套的 else: 语句块。这对“查找-未找到”的场景很有用。
nums = [2, 4, 6, 8]
target = 5
for x in nums:
if x == target:
print('found')
break
else:
print('not found') # 只有当 for 未被 break 打断时才会执行not found
while 也有同样的语义:只要不是被 break 提前跳出,循环结束后就会执行 else。
target = 5
guess = 0
while guess <= 10:
if guess == target:
print('found')
break
guess += 1
else:
print('not found') # 只有没被 break 打断时才会执行found
当使用 while 循环时,我们需要特别注意循环的终止条件。如果 while 后面的条件判断永远为 True,那么循环体内的代码就会被无限次地执行下去,程序就会“卡住”,这就是所谓的无限循环。
注意: 如果陷入无限循环,可以在终端按 Ctrl+C(或在 Jupyter/Quarto 停止内核),必要时再关闭 VS Code!
一个容易犯的错误导致无限循环的例子:
# 警告:下面的代码会导致无限循环,执行时可能需要手动停止程序!
count = 0
while count < 5:
print("这是一个循环...")
# 糟糕!忘记更新 count 的值了 (比如写 count += 1) # 所以 count 永远是 0,count < 5 永远是 True在上面的例子中,因为 count 的值没有在循环体内被修改以最终使 count < 5 这个条件变为 False,所以 print 语句会不停地执行。
如何避免?
确保你的循环体内部有某些操作,能够最终影响到 while 的判断条件,使其在某个时刻变为 False,从而让循环能够正常结束。
while True: 与 break有时,我们确实需要一个循环持续运行,直到某个特定的内部事件发生才停止。在这种情况下,一种常见的模式是使用 while True: 来创建一个表面上的无限循环,然后在循环体内部使用 if 语句来检查某个条件,一旦条件满足,就用 break 语句来强行跳出循环。
示例:等待用户特定输入
while True:
user_input = input("请输入 'quit' 来结束程序: ")
if user_input == "quit":
print("程序已结束。")
break # 如果用户输入了 "quit",跳出循环
else:
print(f"你输入了: {user_input},请继续输入或输入 'quit' 退出。")在这个例子中: 1. while True: 开始了一个循环,它自己永远不会停止。 2. 循环内部,我们获取用户输入。 3. if user_input == "quit": 检查用户是否输入了 quit
。 4. 如果是,break 语句就会执行,立即终止 while 循环。 5. 否则,循环会继续,等待下一次输入。
这种 while True: 结合 break 的方式,为我们提供了一种灵活控制循环何时退出的方法,特别适用于那些退出条件不方便直接放在 while 判断里的情况。
求1~100之间能被7整除,但不能同时被5整除的所有整数。分别写For和While版本
求以下列表平均值。分别写For和While版本。
score = [70, 90, 78, 85, 97, 94, 65, 80]对于一个排序的List,找到某一个元素的位置
思路
a = [ 5,8,15,20,30,45,78,100,120,200 ]
target = 30列表推导式可以让我们从一个可迭代的对象(典型的就是List本身)生成一个List。最常见的情况是从一个List生成另一个List。
例如,把a = [1,2,3,4,5]中的所有数乘以2.
用循环我们可以这样做:
# 循环的版本
a = [1,2,3,4,5]
b = []
for i in a:
b.append(i*2)
print(b)[2, 4, 6, 8, 10]
如果用列表推导式,可以更为简单:
a = [1,2,3,4,5]
b = [i*2 for i in a]
print(b)[2, 4, 6, 8, 10]
一般的结构大概是这样的:
[do_something(i) for i in a_list]
遍历a_list中的每个元素(称之为i),做一个操作,然后结果保存形成一个新的列表。
显然,两端是中括号意味着我们会得到一个新的List。
另一个例子,把列表中的所有字符变为大写。
s = ['abc','abcd','bcde','bcdee','cdefg']
[x.upper() for x in s]['ABC', 'ABCD', 'BCDE', 'BCDEE', 'CDEFG']
也可以结合筛选:遍历list中的元素,选出符合条件的,进行某个操作,形成新的列表。
[do_something(i) for i in a_list if condition(i)]
比如选出a中大于等于3的数,乘以2,再形成一个新的列表。
a = [1,2,3,4,5]
b = [i*2 for i in a if i >=3 ]
print(b)[6, 8, 10]
当然,如果只是要筛选,不做其他操作,上面i*2改成i即可。
a = range(1,6) # 迭代时会产生 1, 2, 3, 4, 5。回忆前文中range和list的区别
b = [i for i in a if i >=3 ]
print(b)[3, 4, 5]
['apple', 'banana', 'ant', 'animal', 'astronaut', 'airplane'].
在推导式中也可以使用条件表达式,但逻辑复杂时建议改回普通循环以保持可读性。
a = [1, 2, 3, 4, 5]
b = [x*2 if x % 2 == 0 else x for x in a]
print(b) # 偶数翻倍,奇数保持不变[1, 4, 3, 8, 5]
字典是映射类型,但它是可迭代的,因此我们也可以遍历字典。
我们可以用 .keys() 和 .values() 获得所有的键与值(均为“视图”对象,如需列表可用 list(...) 转换),也可以用 .items() 同时拿到键和值。
d = {'x': 1, 'y': 3, 'z': 5}
for key in d:
# 或者用 for key in d.keys()
print(key, d[key])x 1
y 3
z 5
d = {'x': 1, 'y': 3, 'z': 5}
for value in d.values():
print(value)1
3
5
我们也介绍过dict可以看作一系列key-value的元组,因此可以遍历items。
回顾:d.items() 返回的是“视图对象”,可迭代地产生 (key, value) 对;如需列表可用 list(d.items())。
d.items() 返回一系列 (键, 值) 对(元组)。在 for 循环中,我们使用 key, value 这种形式来自动地将每个元组中的两个元素分别赋值给 key 和 value 变量,这称为序列解包。
# 遍历每一个(key,value)对,进行某些操作
d = {'x': 1, 'y': 3, 'z': 5}
for key, value in d.items():
print(key, value)x 1
y 3
z 5
和列表推导式类似,字典推导式也可以从一个可迭代对象(比如List,Dict或者任何别的),生成一个字典。
大概的结构如下:
{key:value for i in a_list}
比如,从a = ['Alex','Bob','Clare']生成一个字典,其中key是元素(人名),value是人名的字符长度。
a = ['Alex','Bob','Clare']
len_a = {s:len(s) for s in a}
print(len_a){'Alex': 4, 'Bob': 3, 'Clare': 5}
或者从字典生成一个新字典,key不变,value*2。
d = {'x': 1, 'y': 3, 'z': 5}
e = {key:value*2 for key,value in d.items()}
print(e){'x': 2, 'y': 6, 'z': 10}
ages = {'Alice': 30, 'Bob': 25, 'Charlie': 40, 'Diana': 22}
请使用字典循环遍历,打印出所有年龄大于30的人名。
需要索引时,推荐使用 enumerate;需要并行遍历多个序列时,使用 zip。
a_list = ['a', 'b', 'c']
for idx, val in enumerate(a_list, start=1):
print(idx, val)
names = ['Alice', 'Bob']
scores = [90, 85]
for name, score in zip(names, scores):
print(name, score)1 a
2 b
3 c
Alice 90
Bob 85
在数据分析场景(NumPy/Pandas)中,优先使用“向量化运算、聚合和布尔索引”,通常比 Python 层面的 for 循环更简洁且更快。
&、| 组合条件,并用括号包裹每个子条件;不要用 and/or。import numpy as np
import pandas as pd
# 示例数据
arr = np.arange(1, 6) # array([1, 2, 3, 4, 5])
ser = pd.Series([1, 2, 3, 4, 5]) # 1D 列
# 向量化 vs 循环:求平方
# 循环(不推荐)
squares_loop = []
for x in arr:
squares_loop.append(x ** 2)
# 向量化(推荐)
squares_vec = arr ** 2
# 聚合:求和/均值
total = arr.sum()
mean = ser.mean()
# 布尔筛选与组合条件(注意使用 & 和 |,并加括号)
mask = (ser >= 2) & (ser % 2 == 0) # 选出大于等于2且为偶数
filtered = ser[mask]
print(squares_vec, total, mean)
print(filtered)提示: - 单纯求和/计数等,优先用 sum、mean、value_counts 等聚合方法。 - 在 Pandas 中逐行逻辑尽量避免 for,改用列运算或 np.where、pd.Series.map。
学会使用条件判断和循环,这意味着你的程序现在可以“思考”并“重复工作”了。
核心要点回顾:
if、while、for 等结构至关重要。if, elif, else):
if condition:: 如果条件为 True,执行其下的代码块。elif another_condition:: 在前一个 if 或 elif 条件为 False 时,检查此条件。else:: 如果以上所有条件都为 False,执行此代码块。while condition:: 只要条件为 True,就持续执行其下的代码块。注意避免无限循环,并确保有明确的退出条件或使用 break。for item in iterable:: 遍历可迭代对象(如列表、元组、字符串、range() 对象、字典的键/值/项)中的每一个元素。break: 立即终止并跳出当前所在的整个循环。continue: 立即跳过当前迭代中循环体内的剩余代码,并开始下一次迭代。else 子句: 当循环正常结束(即不是通过 break 跳出)时执行。range(start, stop, step): 生成一个数字序列,常用于 for 循环中控制迭代次数。记住“包含起点,不含终点”。if 和 while 的条件本质上都是布尔表达式,其结果决定了程序的执行路径。[expr for item in iterable if cond]) 和字典推导式 ({k_expr: v_expr for item in iterable if cond}): 提供了一种简洁、高效的方式来从一个可迭代对象创建新的列表或字典。通过条件和循环,你可以让程序自动化地处理更复杂的逻辑和数据。这是构建任何有实际用途的程序的基础。在接下来的学习中,我们将把这些控制流结构与函数结合起来,构建更模块化、更可重用的代码。
while 条件始终为 True,或忘记在循环内改变条件变量;无 break/退出路径。range(start, stop) 不包含 stop;用 <= 循环上界易多算一次。== 写成 =(语法错误);用 is 代替 == 做数值/字符串比较。else 误解:一旦循环被 break 提前跳出,else 不会执行。for 中对同一列表增删元素导致“跳项”;用列表推导式或遍历副本解决。zip 截断:zip 会按最短序列截断,长度不齐会丢数据;如需对齐可用 itertools.zip_longest。and/or 返回参与运算的对象本身,非布尔值;用于“默认值选择”时要注意类型语义。&/| 且每个条件加括号;不要用 and/or。