作者:还怪好嘞 发布时间:2026-05-25 难度:⭐⭐⭐ 阅读时长:约30分钟
前言
程序的核心能力在于决策与重复。条件判断让程序能够根据不同情况做出不同选择,循环控制则让程序能够高效地处理重复性任务。本文将深入讲解Python中的条件判断与循环控制机制,从基础语法到底层原理,助你写出更优雅、更高效的代码。
一、条件判断:程序的智能决策
1.1 if/elif/else 基础语法
Python的条件判断语法简洁直观,使用缩进来表示代码块。
# 基础条件判断score = 85if score >= 90: grade = 'A'elif score >= 80: grade = 'B'elif score >= 70: grade = 'C'elif score >= 60: grade = 'D'else: grade = 'F'print(f"成绩等级: {grade}") # 输出: 成绩等级: B
关键要点:
elif- 条件判断从上到下执行,第一个为True的条件会被执行,其余被跳过
1.2 条件表达式(三元运算符)
Python支持简洁的条件表达式:
# 传统写法if age >= 18: status = "成年人"else: status = "未成年人"# 条件表达式(更简洁)status = "成年人" if age >= 18 else "未成年人"# 嵌套条件表达式(谨慎使用,可读性降低)result = "优秀" if score >= 90 else "良好" if score >= 80 else "及格" if score >= 60 else "不及格"
1.3 match-case 模式匹配(Python 3.10+)
Python 3.10引入了match-case语句,提供更强大的模式匹配能力:
def handle_command(command): match command: case "start": return "启动系统" case "stop": return "停止系统" case "restart": return "重启系统" case _: return f"未知命令: {command}"# 带数据提取的模式匹配def analyze_point(point): match point: case (0, 0): return "原点" case (x, 0): return f"x轴上的点,x={x}" case (0, y): return f"y轴上的点,y={y}" case (x, y): return f"普通点,坐标({x}, {y})" case _: return "不是有效的点"print(analyze_point((3, 0))) # 输出: x轴上的点,x=3
match-case vs if-elif 对比:
二、布尔值的本质
2.1 真值测试规则
在Python中,以下值被视为False:
NoneFalse- 空序列:
'', [], (), {}, set(), range(0)
其余所有值都被视为True。
# 真值测试示例values = [0, 1, "", "hello", [], [1, 2], None, True]for v in values: if v: print(f"{v!r} 是真值") else: print(f"{v!r} 是假值")
2.2 短路求值
Python的and和or运算符使用短路求值:
# and: 第一个为False就返回第一个值,否则返回第二个值result1 = 0 and 100 # 结果: 0result2 = 50 and 100 # 结果: 100# or: 第一个为True就返回第一个值,否则返回第二个值result3 = 0 or 100 # 结果: 100result4 = 50 or 100 # 结果: 50# 实用技巧:设置默认值name = user_input or "匿名用户"
三、循环控制:重复的艺术
3.1 for 循环
Python的for循环用于遍历可迭代对象:
# 遍历列表fruits = ["苹果", "香蕉", "橙子"]for fruit in fruits: print(fruit)# 使用enumerate获取索引for index, fruit in enumerate(fruits): print(f"{index}: {fruit}")# 遍历字典student = {"name": "张三", "age": 20, "grade": "A"}for key, value in student.items(): print(f"{key} = {value}")# 同时遍历多个序列names = ["Alice", "Bob", "Charlie"]scores = [85, 92, 78]for name, score in zip(names, scores): print(f"{name}: {score}")
3.2 while 循环
while循环在条件为True时持续执行:
# 基础while循环count = 0while count < 5: print(count) count += 1# 带else的while循环(循环正常结束时执行)attempts = 3while attempts > 0: password = input("请输入密码: ") if password == "secret": print("登录成功!") break attempts -= 1else: print("密码错误次数过多,账户已锁定")
3.3 range() 的惰性求值
range()函数返回一个惰性求值的序列对象,而非列表:
# range() 返回的是 range 对象,不是列表r = range(1000000)print(type(r)) # <class 'range'>print(len(r)) # 1000000# 惰性求值:只在需要时生成值# 内存占用极小,无论范围多大# range的三种用法range(5) # 0, 1, 2, 3, 4range(1, 6) # 1, 2, 3, 4, 5range(0, 10, 2) # 0, 2, 4, 6, 8
底层原理:range对象存储的是起始值、终止值、步长三个参数,通过__getitem__方法在访问时动态计算值,因此内存占用恒定为O(1)。
3.4 循环控制语句
# break: 立即退出循环for i in range(10): if i == 5: break print(i) # 输出: 0, 1, 2, 3, 4# continue: 跳过当前迭代for i in range(5): if i == 2: continue print(i) # 输出: 0, 1, 3, 4# else: 循环正常完成时执行(未被break中断)for i in range(3): print(i)else: print("循环正常结束") # 会执行for i in range(3): if i == 1: breakelse: print("循环正常结束") # 不会执行
四、推导式:Pythonic的优雅写法
4.1 列表推导式
# 传统写法squares = []for x in range(10): squares.append(x ** 2)# 列表推导式squares = [x ** 2 for x in range(10)]# 带条件的列表推导式even_squares = [x ** 2 for x in range(10) if x % 2 == 0]# 结果: [0, 4, 16, 36, 64]# 嵌套列表推导式matrix = [[i * j for j in range(1, 4)] for i in range(1, 4)]# 结果: [[1, 2, 3], [2, 4, 6], [3, 6, 9]]
4.2 字典和集合推导式
# 字典推导式word_lengths = {word: len(word) for word in ["apple", "banana", "cherry"]}# 结果: {'apple': 5, 'banana': 6, 'cherry': 6}# 集合推导式unique_lengths = {len(word) for word in ["apple", "banana", "cherry", "date"]}# 结果: {4, 5, 6}# 生成器表达式(惰性求值)sum_of_squares = sum(x ** 2 for x in range(1000000)) # 内存友好
4.3 推导式性能对比
import time# 测试数据data = list(range(100000))# 方法1: 传统for循环def method_loop(): result = [] for x in data: if x % 2 == 0: result.append(x * 2) return result# 方法2: 列表推导式def method_comprehension(): return [x * 2 for x in data if x % 2 == 0]# 方法3: map + filterdef method_map_filter(): return list(map(lambda x: x * 2, filter(lambda x: x % 2 == 0, data)))# 性能测试for name, func in [("Loop", method_loop), ("Comprehension", method_comprehension), ("Map+Filter", method_map_filter)]: start = time.time() for _ in range(100): func() print(f"{name}: {time.time() - start:.4f}s")
性能对比结果(典型值):
推导式更快的原因:
五、实战项目
5.1 猜数字游戏
import randomdef guessing_game(): """猜数字游戏 - 综合应用条件判断和循环""" secret = random.randint(1, 100) attempts = 0 max_attempts = 7 print("=" * 40) print("🎮 欢迎来到猜数字游戏!") print(f"我想了一个1-100之间的数字,你有{max_attempts}次机会") print("=" * 40) while attempts < max_attempts: try: guess = int(input(f"\n第{attempts + 1}次尝试,请输入你的猜测: ")) attempts += 1 if guess < 1 or guess > 100: print("⚠️ 请输入1-100之间的数字!") continue if guess < secret: print("📉 太小了!再大一点") elif guess > secret: print("📈 太大了!再小一点") else: print(f"\n🎉 恭喜你!用了{attempts}次就猜对了!") return except ValueError: print("⚠️ 请输入有效的数字!") print(f"\n😢 游戏结束!正确答案是 {secret}")if __name__ == "__main__": guessing_game()
5.2 九九乘法表
def multiplication_table(): """打印九九乘法表 - 嵌套循环应用""" print("=" * 60) print(" 九九乘法表") print("=" * 60) # 左下角版本 print("\n【左下角版本】") for i in range(1, 10): for j in range(1, i + 1): print(f"{j}×{i}={i*j:2}", end=" ") print() # 右上角版本 print("\n【右上角版本】") for i in range(1, 10): # 打印前导空格 print(" " * (9 - i), end="") for j in range(i, 10): print(f"{i}×{j}={i*j:2}", end=" ") print()multiplication_table()
5.3 FizzBuzz经典问题
def fizzbuzz(n=100): """ FizzBuzz问题: - 3的倍数输出Fizz - 5的倍数输出Buzz - 同时是3和5的倍数输出FizzBuzz """ results = [] for i in range(1, n + 1): if i % 15 == 0: results.append("FizzBuzz") elif i % 3 == 0: results.append("Fizz") elif i % 5 == 0: results.append("Buzz") else: results.append(str(i)) return results# 使用推导式的优雅写法def fizzbuzz_elegant(n=100): return [ "Fizz" * (i % 3 == 0) + "Buzz" * (i % 5 == 0) or str(i) for i in range(1, n + 1) ]# 测试print("前20个结果:")print(fizzbuzz(20))print("\n优雅写法结果:")print(fizzbuzz_elegant(20))
5.4 矩阵转置
def transpose_matrix(matrix): """矩阵转置 - 多种实现方式对比""" # 方法1: 传统循环 def method_loop(m): rows, cols = len(m), len(m[0]) result = [] for j in range(cols): new_row = [] for i in range(rows): new_row.append(m[i][j]) result.append(new_row) return result # 方法2: 列表推导式 def method_comprehension(m): return [[m[i][j] for i in range(len(m))] for j in range(len(m[0]))] # 方法3: zip函数(最Pythonic) def method_zip(m): return [list(row) for row in zip(*m)] # 测试 print("原始矩阵:") for row in matrix: print(row) print("\n转置后 (zip方法):") result = method_zip(matrix) for row in result: print(row) return result# 测试matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9]]transpose_matrix(matrix)
六、常见陷阱与最佳实践
6.1 陷阱1:循环中的可变默认参数
# ❌ 错误:在循环中修改正在迭代的列表numbers = [1, 2, 3, 4, 5]for n in numbers: if n % 2 == 0: numbers.remove(n) # 危险!会导致跳过元素print(numbers) # 结果可能不符合预期# ✅ 正确:创建新列表或遍历副本numbers = [1, 2, 3, 4, 5]numbers = [n for n in numbers if n % 2 != 0] # 推荐# 或for n in numbers[:]: # 遍历副本 if n % 2 == 0: numbers.remove(n)
6.2 陷阱2:range的边界问题
# ❌ 容易混淆:range是左闭右开for i in range(1, 5): print(i) # 输出 1, 2, 3, 4(不包含5)# ✅ 记忆技巧:range(start, stop) 包含start,不包含stop# range(n) 等价于 range(0, n)
6.3 陷阱3:循环变量泄漏
# Python 3中,循环变量不会泄漏到外部作用域for i in range(5): passprint(i) # Python 3中输出 4(最后一次的值)# 但在列表推导式中,变量不会泄漏x = 'before'[y for x in range(5)]print(x) # 输出 'before'(Python 3中)
6.4 陷阱4:空容器的真值判断
# ❌ 不推荐if len(my_list) == 0: print("列表为空")# ✅ 推荐:直接使用真值测试if not my_list: print("列表为空")if my_list: # 列表非空 print("列表有元素")
6.5 最佳实践总结
| | |
|---|
| for item in items | for i in range(len(items)) |
| enumerate(items) | |
| zip(list1, list2) | |
| | map |
| | |
七、本章小结
核心知识点回顾
- 条件判断:
if/elif/else用于分支决策,match-case提供模式匹配能力 - 布尔值本质
- 循环控制
- 循环控制语句:
break退出,continue跳过,else处理正常结束 - 推导式:列表/字典/集合推导式提供简洁高效的数据处理方式
底层原理要点
八、课后练习
基础练习
等级判断器:编写程序,根据输入的百分制成绩输出等级(A:90+, B:80+, C:70+, D:60+, F:60-)
素数筛选:使用埃拉托斯特尼筛法,找出100以内的所有素数
列表去重:给定列表[1, 2, 2, 3, 3, 3, 4],使用推导式去重并保持顺序
进阶练习
打印菱形:编写程序打印如下菱形图案:
* *** ************ ***** *** *
单词频率统计:给定一段文本,统计每个单词出现的次数(使用字典推导式)
矩阵乘法:实现两个矩阵的乘法运算
挑战练习
八皇后问题:使用回溯算法解决八皇后问题,找出所有解法
推导式性能测试:编写程序对比不同规模数据下,循环、推导式、map/filter的性能差异
参考资源
💡 学习建议:条件判断和循环是编程的基础,建议通过大量练习形成肌肉记忆。特别要掌握推导式的使用,这是写出Pythonic代码的关键。
本文是《Python全栈修炼之路》系列第6篇,持续更新中,欢迎关注专栏获取更多内容!