= 98
price 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 语句:
= 98
price if price <100:
print('buy')
buy
if-else语句:
= 102
price if price <100:
print('buy')
else:
print('not buy')
not buy
if-elif语句:
= 102
price if price <100:
print('buy')
elif price < 110:
print('hold')
elif price < 120:
print('think about it')
else:
print('sell')
hold
= 70
price if price<80: print('buy')
buy
小提示:实际项目中更推荐使用多行 if
,可读性更好。
= 85
price "buy" if (price < 80) else "don't buy"
"don't buy"
练习1:小明身高1.75m,体重80.5kg。请根据BMI公式(体重除以身高的平方)帮小明计算他的BMI指数,并根据BMI指数:
用if-elif判断并打印结果:
小提示:
= 1.75
height = 80.5
weight
# 计算BMI指数
# 用 if-elif 判断,并打印结果
# 提示:可以使用链式比较,比如 18.5 <= bmi < 25
练习2:判断闰年:从year, 判断是否为闰年?
提示1: 闰年: 年份能被4整除但不能被100整除的 或者 能被400整除
提示2: 判断一个数字能否被某个数整除,可以判断其余数(取余运算是%
)是否为0,如a % 2 == 0
如果为True
则为偶数。
注:可以用多层的条件语句,或者用多个逻辑运算来写。
= 2005 # 或者任何一年 year
例子:用if-else求a、b、c 3个数中最大的一个
思路:
= 4
a = 9
b = 2
c
if a>b:
if a>c:
=a
max_valueelse:
=c
max_valueelse:
if b>c:
=b
max_valueelse:
=c
max_value
print(f"最大值是{max_value}")
最大值是9
对一个变量number,判断是否能被2或者3整除
按具体的情况,请输出:
思路:
前面讲过,布尔型有2种,真True
和假False
。
实际上,这2个符号,是布尔型变量的值,和1,2,3,4
是整型的值,'apple'
是字符串的值类似。但布尔型的值只有2种。
例如,有一个变量,用于表示“现在是否下雨”。这个问题只有2个答案,是或者否,显然这就可以用布尔型来表示:True
就表示下雨,False
就表示没下雨。我们就定义一个布尔型变量is_raining
。
注意:为了达到顾名思义的效果,布尔型的变量,可以考虑用is_
,has_
等等开头,显示这是个“是否”问题的答案。
# 表示现在正在刮风下雨
= True
is_raining = True is_windy
判断是否同时在刮风和下雨
print(is_raining and is_windy)
True
布尔运算,其结果,也是一个布尔类型的变量:因此可以赋值给另一个变量。
bad_weather
= is_raining and is_windy # 布尔运算的结果,也是一个布尔型,并且可以赋值给另一个变量
bad_weather print(bad_weather)
True
换一种理解,你可以把and
运算,看成一个函数。类似于:
bool_and(x, y)
就可以视为一个函数调用,返回的结果,就是与操作
= bool_and(is_raining, is_windy) # 这是随便写的,无法执行 bad_weather
回到我们的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
,是等价的。但后者可以少进行一次赋值的操作,并且节约一个变量名。
回看前面的例子:
= 2
a = 3
b if a > b:
print('a > b')
else:
print('a <= b')
a <= b
可以把a > b
看成是“一个布尔型的变量”,这个变量,保存了a > b
的结果,只是我们没有把这个结果赋值给一个变量名(没有绑定一个标签),而是直接放进了if
语句中。
这等价于:
= 2
a = 3
b
= a > b
is_a_bigger
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
while循环比较直观,“只要条件成立,就重复执行某块代码块”
或者说,“重复执行某块代码块,直到条件不成立为止”
while 判断条件(condition):
执行语句(statements)
思想:
+=
例如 i += 2
即让i
自增2,等价于 i = i + 2
= 1
i += 2
i print(i)
3
设计一个从1到10的循环
= 1
i while i <= 10:
print(i)
+=1
i
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]
中的每一个元素,执行打印这个动作。
= [1,2,3,4,5]
a_list
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
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将不会被执行
# 只打印列表中的奇数
= [1, 2, 3, 4, 5, 6]
numbers for num in numbers:
if num % 2 == 0: # 如果是偶数
continue # 跳过本次循环中后续的print语句,直接开始下一次迭代
print(num) # 这行只在num是奇数时执行
1
3
5
当循环“正常结束”(即不是通过 break
提前跳出)时,会执行与之配套的 else:
语句块。这对“查找-未找到”的场景很有用。
= [2, 4, 6, 8]
nums = 5
target
for x in nums:
if x == target:
print('found')
break
else:
print('not found') # 只有当 for 未被 break 打断时才会执行
not found
当使用 while
循环时,我们需要特别注意循环的终止条件。如果 while
后面的条件判断永远为 True
,那么循环体内的代码就会被无限次地执行下去,程序就会“卡住”,这就是所谓的无限循环。
注意: 如果陷入无限循环,可以直接关闭vscode!
一个容易犯的错误导致无限循环的例子:
# 警告:下面的代码会导致无限循环,执行时可能需要手动停止程序!
= 0
count 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:
= input("请输入 'quit' 来结束程序: ")
user_input 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版本。
= [70, 90, 78, 85, 97, 94, 65, 80] score
对于一个排序的List,找到某一个元素的位置
思路
= [ 5,8,15,20,30,45,78,100,120,200 ]
a = 30 target
列表推导式可以让我们从一个可迭代的对象(典型的就是List本身)生成一个List。最常见的情况是从一个List生成另一个List。
例如,把a = [1,2,3,4,5]
中的所有数乘以2.
用循环我们可以这样做:
# 循环的版本
= [1,2,3,4,5]
a = []
b
for i in a:
*2)
b.append(i
print(b)
[2, 4, 6, 8, 10]
如果用列表推导式,可以更为简单:
= [1,2,3,4,5]
a = [i*2 for i in a]
b print(b)
[2, 4, 6, 8, 10]
一般的结构大概是这样的:
[do_something(i) for i in a_list]
遍历a_list中的每个元素(称之为i),做一个操作,然后结果保存形成一个新的列表。
显然,两端是中括号意味着我们会得到一个新的List。
另一个例子,把列表中的所有字符变为大写。
= ['abc','abcd','bcde','bcdee','cdefg']
s for x in s] [x.upper()
['ABC', 'ABCD', 'BCDE', 'BCDEE', 'CDEFG']
也可以结合筛选:遍历list中的元素,选出符合条件的,进行某个操作,形成新的列表。
[do_something(i) for i in a_list if condition(i)]
比如选出a中大于等于3的数,乘以2,再形成一个新的列表。
= [1,2,3,4,5]
a = [i*2 for i in a if i >=3 ]
b print(b)
[6, 8, 10]
当然,如果只是要筛选,不做其他操作,上面i*2
改成i
即可。
= range(1,6) # 迭代时会产生 1, 2, 3, 4, 5。回忆前文中range和list的区别
a = [i for i in a if i >=3 ]
b print(b)
[3, 4, 5]
['apple', 'banana', 'ant', 'animal', 'astronaut', 'airplane']
.
在推导式中也可以使用条件表达式,但逻辑复杂时建议改回普通循环以保持可读性。
= [1, 2, 3, 4, 5]
a = [x*2 if x % 2 == 0 else x for x in a]
b print(b) # 偶数翻倍,奇数保持不变
[1, 4, 3, 8, 5]
字典是映射类型,但它是可迭代的,因此我们也可以遍历字典。
我们可以用 .keys()
和 .values()
获得所有的键与值(均为“视图”对象,如需列表可用 list(...)
转换),也可以用 .items()
同时拿到键和值。
= {'x': 1, 'y': 3, 'z': 5}
d for key in d:
# 或者用 for key in d.keys()
print(key, d[key])
x 1
y 3
z 5
= {'x': 1, 'y': 3, 'z': 5}
d for value in d.values():
print(value)
1
3
5
我们也介绍过dict可以看作一系列key-value的元组,因此可以遍历items。
回顾:d.items()可以返回 [(key,value),(key,value),...]
的结构。
d.items()
返回一系列 (键, 值) 对(元组)。在 for
循环中,我们使用 key, value
这种形式来自动地将每个元组中的两个元素分别赋值给 key
和 value
变量,这称为序列解包。
# 遍历每一个(key,value)对,进行某些操作
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是人名的字符长度。
= ['Alex','Bob','Clare']
a = {s:len(s) for s in a}
len_a print(len_a)
{'Alex': 4, 'Bob': 3, 'Clare': 5}
或者从字典生成一个新字典,key不变,value*2。
= {'x': 1, 'y': 3, 'z': 5}
d = {key:value*2 for key,value in d.items()}
e print(e)
{'x': 2, 'y': 6, 'z': 10}
ages = {'Alice': 30, 'Bob': 25, 'Charlie': 40, 'Diana': 22}
请使用字典循环遍历,打印出所有年龄大于30的人名。
需要索引时,推荐使用 enumerate
;需要并行遍历多个序列时,使用 zip
。
= ['a', 'b', 'c']
a_list for idx, val in enumerate(a_list, start=1):
print(idx, val)
= ['Alice', 'Bob']
names = [90, 85]
scores for name, score in zip(names, scores):
print(name, score)
1 a
2 b
3 c
Alice 90
Bob 85
学会使用条件判断和循环,这意味着你的程序现在可以“思考”并“重复工作”了。
核心要点回顾:
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}
): 提供了一种简洁、高效的方式来从一个可迭代对象创建新的列表或字典。常见错误提示 (本章相关):
IndentationError
: 缩进不正确或不一致。while
循环的条件永远为 True
,且没有 break
。if
条件的判断逻辑不符合预期,或比较运算符使用错误(如把 ==
写成 =
)。TypeError
/ NameError
: 在循环或条件判断中使用了未定义或类型不兼容的变量。通过条件和循环,你可以让程序自动化地处理更复杂的逻辑和数据。这是构建任何有实际用途的程序的基础。在接下来的学习中,我们将把这些控制流结构与函数结合起来,构建更模块化、更可重用的代码。
while
条件永远为 True 且没有 break
。检查循环内是否有能改变条件的语句。range(start, stop)
不包含 stop
,容易少算或多算一次。==
错写成 =
(语法错误),或将 is
误用作数值比较。my_list[idx]
超出范围抛 IndexError
;访问不存在的字典键抛 KeyError
,可用 in
检查或 dict.get(key, default)
。