8. 使用 if 语句做决策
在我们目前写过的程序中,Python 会从上到下执行每一行代码,一条语句接着一条语句地运行。但真实世界的程序需要做决策——根据不同条件执行不同的代码。我们是否应该显示一条错误消息?是否应该计算折扣?是否应该再次请求输入?答案取决于具体情况。
条件语句 (conditional statements) 让你的程序能够做出这些决策。它们允许 Python 仅在特定条件为真时执行某些代码块,否则就跳过它们。本章将介绍 Python 的 if 语句及其变体,它们构成了程序中决策能力的基础。
通过掌握条件语句,你将能够编写能对用户输入做出智能响应的程序,恰当地处理不同场景,并解决需要逻辑推理的问题。
8.1) 简单的 if 语句
Python 中最基本的决策形式是 简单 if 语句 (simple if statement)。它告诉 Python:“如果这个条件为真,就执行这段代码块。否则跳过它并继续。”
8.1.1) if 语句的结构
下面是 if 语句的基本语法:
if condition:
# 当 condition 为 True 时要执行的代码
statement1
statement2
# ... 更多语句我们来分解一下每个部分:
if关键字:这会开始一个条件语句- 条件:一个会计算为
True或False的布尔表达式(来自第 7 章) - 冒号 (
:):这是必需的,用来标记条件行的结束 - 缩进的代码块:所有缩进在
if之下的语句,只有当条件为True时才会执行
缩进在 Python 中至关重要。 缩进的行构成了属于 if 语句的 代码块 (code block)。Python 使用缩进(通常为 4 个空格)来确定哪些语句属于条件块的一部分。
下面是一个简单示例:
# temperature_check.py
temperature = 30
if temperature > 25:
print("It's a warm day!")
print("Consider wearing light clothing.")
print("Have a great day!") # 这行总会执行Output:
It's a warm day!
Consider wearing light clothing.
Have a great day!在这个示例中:
- 条件
temperature > 25的计算结果为True(因为 30 > 25) - 两条缩进的
print()语句会执行,因为它们是if块的一部分 - 最后一条
print()语句总会执行,因为它没有缩进——它不是if块的一部分
现在让我们看看条件为 False 时会发生什么:
# temperature_check_cool.py
temperature = 18
if temperature > 25:
print("It's a warm day!")
print("Consider wearing light clothing.")
print("Have a great day!") # 这行总会执行Output:
Have a great day!这一次:
- 条件
temperature > 25的计算结果为False(因为 18 并不大于 25) - 两条缩进语句会被完全跳过
- 只有最后的
print()会执行,因为它在if块之外
8.1.2) 使用第 7 章中的条件
第 7 章中的任何布尔表达式都可以用作 if 语句中的条件。这包括:
比较运算符:
# voting_eligibility.py
age = 16
if age >= 18:
print("You are eligible to vote.")
# 因为 16 >= 18 为 False,所以不会打印任何内容
score = 85
if score >= 60:
print("You passed the exam!") # Output: You passed the exam!使用 in 和 not in 的成员测试:
# user_access.py
username = "alice"
banned_users = ["bob", "charlie", "dave"]
if username not in banned_users:
print(f"Welcome, {username}!") # Output: Welcome, alice!
favorite_color = "blue"
if "u" in favorite_color:
print("Your favorite color contains the letter 'u'.") # Output: Your favorite color contains the letter 'u'.直接使用布尔值:
# weather_check.py
is_raining = True
if is_raining:
print("Don't forget your umbrella!") # Output: Don't forget your umbrella!真值与假值 (truthiness and falsiness)(来自第 7.4 节):
# name_input.py
user_input = input("Enter your name: ")
if user_input: # 空字符串是假值,非空字符串是真值
print(f"Hello, {user_input}!")
else:
print("You didn't enter a name.")8.1.3) 在 if 块中包含多条语句
你可以在 if 块中包含任意多条语句。if 行下面所有缩进的语句都属于该代码块:
# bank_withdrawal.py
balance = 1500
withdrawal = 200
if withdrawal <= balance:
balance = balance - withdrawal # 从 balance 中减去 withdrawal
print(f"Withdrawal successful!")
print(f"Your new balance is: ${balance}")
print("Thank you for your transaction.")
print("Transaction complete.") # 总会执行Output:
Withdrawal successful!
Your new balance is: $1300
Thank you for your transaction.
Transaction complete.四条语句都会执行,因为 withdrawal <= balance 为 True。如果我们把取款金额改成 2000:
# bank_withdrawal_insufficient.py
balance = 1500
withdrawal = 2000
if withdrawal <= balance:
balance = balance - withdrawal
print(f"Withdrawal successful!")
print(f"Your new balance is: ${balance}")
print("Thank you for your transaction.")
print("Transaction complete.") # 总会执行Output:
Transaction complete.现在由于条件为 False,所有缩进语句都不会执行。余额仍保持为 1500,不会改变。
8.2) 使用 if-else 进行二选一
很多时候你需要在两个备选项之间做选择:如果条件为真就执行一段代码块,如果为假则执行另一段代码块。if-else 语句 (if-else statement) 用于处理这种二选一的决策。
8.2.1) if-else 的结构
语法如下:
if condition:
# 当 condition 为 True 时要执行的代码
statement1
statement2
else:
# 当 condition 为 False 时要执行的代码
statement3
statement4else 子句提供了一条替代路径。两个代码块中恰好会执行一个——不会两者都执行,也不会两者都不执行。
我们来看一个实际例子:
# age_verification.py
age = int(input("Enter your age: "))
if age >= 18:
print("You are an adult.")
print("You can vote in elections.")
else:
print("You are a minor.")
print("You cannot vote yet.")
print("Thank you for providing your age.")如果你输入 25:
You are an adult.
You can vote in elections.
Thank you for providing your age.如果你输入 15:
You are a minor.
You cannot vote yet.
Thank you for providing your age.注意两个代码块中恰好会执行一个,取决于条件。最后的 print() 语句总会执行,因为它在两个代码块之外。
8.2.2) 做二元决策
if-else 非常适合只有两种可能结果的二元决策:
# even_odd_checker.py
number = int(input("Enter a number: "))
if number % 2 == 0:
print(f"{number} is even.")
else:
print(f"{number} is odd.")# password_verification.py
stored_password = "python123"
entered_password = input("Enter password: ")
if entered_password == stored_password:
print("Access granted.")
print("Welcome to the system!")
else:
print("Access denied.")
print("Incorrect password.")8.3) 使用 if-elif-else 处理多个选择
现实世界的决策往往不止两个选项。我们应该收取标准运费、加急运费还是隔夜运费?成绩是 A、B、C、D 还是 F?if-elif-else 链 (if-elif-else chain) 用于处理多个互斥的备选项。
8.3.1) if-elif-else 的结构
语法如下:
if condition1:
# 当 condition1 为 True 时执行
block1
elif condition2:
# 当 condition1 为 False 且 condition2 为 True 时执行
block2
elif condition3:
# 当 condition1 和 condition2 都为 False,且 condition3 为 True 时执行
block3
else:
# 当所有条件都为 False 时执行
block4关于 if-elif-else 链的关键点:
elif是 “else if” 的缩写:它提供了额外要检查的条件- 顺序很重要:Python 从上到下检查条件
- 先匹配者生效:一旦某个条件为
True,对应代码块就会执行,其余条件会被跳过 - 恰好执行一个代码块:链中最多只有一个代码块会运行
else是可选的:它会捕获前面条件未处理的所有情况
我们来看一个实际例子:
# grade_calculator.py
score = int(input("Enter your exam score (0-100): "))
if score >= 90:
grade = "A"
print("Excellent work!")
elif score >= 80:
grade = "B"
print("Good job!")
elif score >= 70:
grade = "C"
print("Satisfactory.")
elif score >= 60:
grade = "D"
print("You passed, but consider reviewing the material.")
else:
grade = "F"
print("Unfortunately, you did not pass.")
print(f"Your grade is: {grade}")如果你输入 85:
Good job!
Your grade is: B我们来追踪一下发生了什么:
- 检查
score >= 90:False(85 不 >= 90),所以跳过该代码块 - 检查
score >= 80:True(85 >= 80),所以执行该代码块 - 因为找到了匹配项,跳过所有剩余的
elif和else代码块
如果你输入 55:
Unfortunately, you did not pass.
Your grade is: F所有条件都为 False,因此会执行 else 块。
8.3.2) 为什么 elif 链中的顺序很重要
条件的顺序至关重要,因为 Python 一旦找到 True 条件就会停止继续检查。考虑下面这个错误的评分系统:
# 顺序不正确 - 不要这样做!
score = 85
if score >= 60: # 这里会先匹配!
grade = "D"
elif score >= 70:
grade = "C"
elif score >= 80:
grade = "B"
elif score >= 90:
grade = "A"
else:
grade = "F"
print(f"Your grade is: {grade}") # Output: Your grade is: D这会给出错误的结果!85 分应该是 B,但它得到了 D,因为先检查了 score >= 60 并且它为 True。Python 永远不会检查到 score >= 80 这个条件。
始终将条件从最具体到最不具体进行排序:
# 正确的顺序
score = 85
if score >= 90: # 最具体
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
elif score >= 60:
grade = "D"
else: # 最不具体
grade = "F"
print(f"Your grade is: {grade}") # Output: Your grade is: B8.3.3) 使用不带 else 的 elif
else 子句是可选的。有时你只想处理特定情况,而对其他情况什么都不做:
# weekend_checker.py
day = input("Enter a day of the week: ").lower()
if day == "saturday" or day == "sunday":
print("It's the weekend! Time to relax.")
elif day == "friday":
print("It's Friday! The weekend is almost here.")
elif day in ["monday", "tuesday", "wednesday", "thursday"]:
print("It's a weekday. Time to work or study.")
# 没有 else 子句——如果都不匹配,就什么也不发生
print("Have a great day!")如果你输入 "holiday":
Have a great day!没有条件匹配,并且没有 else 子句,所以只有最后的 print() 会执行。
8.4) 嵌套 if 语句
有时你需要在一个决策中再做另一个决策。嵌套 if 语句 (nested if statements) 是把一个条件语句放在另一个条件语句中,这样你就能在初始条件满足之后再检查额外条件。
8.4.1) 理解嵌套条件语句
嵌套 if 语句很强大,因为它们让你避免检查那些尚不合理的条件。例如,如果用户没有账户,就没有必要询问密码。嵌套可以让你按真实世界的决策过程来组织逻辑:有些问题只有在其他问题先得到回答后才有意义。
一个嵌套的 if 语句,简单来说就是在另一个 if 块内部放一个 if 语句(或 if-elif-else 链):
if outer_condition:
# 当 outer_condition 为 True 时执行这段代码
if inner_condition:
# 当两个条件都为 True 时执行这段代码
inner_block
else:
# 当 outer_condition 为 True 但 inner_condition 为 False 时执行
inner_else_block
else:
# 当 outer_condition 为 False 时执行
outer_else_block只有当外层条件为 True 时,内层 if 语句才会被计算。这会创建一个决策的层级结构。
下面是一个简单示例:
# account_login.py
has_account = input("Do you have an account? (yes/no): ").lower() == "yes"
if has_account:
print("Welcome back!")
password = input("Enter your password: ")
if password == "secret123":
print("Login successful!")
print("Access granted to your dashboard.")
else:
print("Incorrect password.")
print("Access denied.")
else:
print("Please create an account first.")
print("Visit our registration page.")如果你回答 "yes" 并输入正确密码:
Welcome back!
Login successful!
Access granted to your dashboard.如果你回答 "yes" 但输入错误密码:
Welcome back!
Incorrect password.
Access denied.如果你回答 "no":
Please create an account first.
Visit our registration page.注意密码检查只有在用户有账户时才会发生。这就是嵌套的关键好处——你可以避免不必要的检查。
8.4.2) 何时使用嵌套 if 语句
嵌套 if 语句在以下情况很有用:
- 决策依赖前一个决策:只有在满足某个条件后才需要检查另一个内容
- 创建决策树:每一层都会缩小可能性
- 验证前置条件:在检查更细节的要求之前先检查基本要求
- 避免不必要的检查:当早期条件失败时跳过开销较大的操作
示例:贷款资格
# loan_eligibility.py
age = int(input("Enter your age: "))
if age >= 18:
print("Age requirement met.")
income = float(input("Enter your annual income: $"))
if income >= 30000:
print("Income requirement met.")
credit_score = int(input("Enter your credit score: "))
if credit_score >= 650:
print("Congratulations! You are eligible for a loan.")
print("Please proceed to the application form.")
else:
print("Sorry, your credit score is too low.")
print("Minimum required: 650")
else:
print("Sorry, your income is too low.")
print("Minimum required: $30,000")
else:
print("Sorry, you must be 18 or older to apply.")这会创建一个决策树,其中每一层都依赖于前一层。如果年龄小于 18,我们就不会再询问收入或信用评分。
8.4.3) 避免过度嵌套
虽然嵌套很强大,但层级过多会让代码难以阅读和理解。考虑下面这个深度嵌套的示例:
# 嵌套太深 - 很难看懂
if condition1:
if condition2:
if condition3:
if condition4:
if condition5:
print("All conditions met!")这很难阅读和维护。以下是减少嵌套的策略:
策略 1:在合适时合并条件
我们会在第 9 章详细学习 and 运算符,但现在只需要知道它可以让你一次检查多个条件:
# 更好:使用 'and' 合并条件(第 9 章会完整解释)
# 我们将在第 9 章学习 'and',但现在只要知道它会检查
# 所有条件是否都为真
if condition1 and condition2 and condition3 and condition4 and condition5:
print("All conditions met!")策略 2:使用提前返回(在使用函数时,我们会在第 19 章学习):
# 在函数中,我们可以提前 return
def check_eligibility(age, income, credit_score):
if age < 18:
return "Too young"
if income < 30000:
return "Income too low"
if credit_score < 650:
return "Credit score too low"
return "Eligible"策略 3:在合适时用 elif 展平:
# 不用嵌套 if 来检查范围,而是用 elif
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
# ... 依此类推8.5) 常见的 if 语句陷阱(缩进、冒号与逻辑)
即使是有经验的程序员也会在 if 语句上犯错。本节涵盖初学者最常遇到的错误以及如何避免它们。
8.5.1) 缩进错误
Python 使用缩进来确定哪些语句属于哪个代码块。错误的缩进是最常见的错误来源之一。
问题 1:缺少缩进
# 错误 - IndentationError
age = 20
if age >= 18:
print("You are an adult.") # 没有缩进!这会产生:
File "example.py", line 4
print("You are an adult.")
^
IndentationError: expected an indented block解决方案:始终缩进 if 语句下方的代码块:
# 正确
age = 20
if age >= 18:
print("You are an adult.") # 缩进正确问题 2:缩进不一致
# 错误 - 混用空格与制表符,或空格数量不一致
if temperature > 30:
print("It's hot!")
print("Stay hydrated!") # 多了空格 - 缩进不一致解决方案:使用一致的缩进(4 个空格是 Python 的标准):
# 正确
if temperature > 30:
print("It's hot!")
print("Stay hydrated!") # 相同的缩进层级问题 3:嵌套层级缩进错误
# 错误 - 缩进层级不正确
if has_account:
print("Welcome!")
if password == "correct":
print("Login successful!") # 应该再多缩进一层解决方案:每增加一层嵌套都需要额外缩进:
# 正确
if has_account:
print("Welcome!")
if password == "correct":
print("Login successful!") # 嵌套块缩进正确8.5.2) 缺少冒号
if、elif 和 else 行末尾的冒号 (:) 是必需的。忘记它是非常常见的错误:
# 错误 - SyntaxError: missing colon
if age >= 18
print("Adult")这会产生:
File "example.py", line 2
if age >= 18
^
SyntaxError: invalid syntax解决方案:始终包含冒号:
# 正确
if age >= 18:
print("Adult")对 elif 和 else 也是一样:
# 正确 - 所有冒号都存在
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
else:
grade = "F"8.5.3) 错误的比较运算符
问题 1:使用赋值 (=) 代替比较 (==)
# 错误 - 这会把 18 赋值给 age,而不是比较!
age = 20
if age = 18: # SyntaxError
print("You are 18")解决方案:使用 == 进行比较:
# 正确
age = 20
if age == 18:
print("You are 18")8.5.4) 由于逻辑错误导致代码不可达
问题:永远不可能为 True 的条件
# 错误 - elif 永远不会执行
score = 85
if score >= 60:
print("You passed!")
elif score >= 80: # This will never execute!
print("You got a B!")如果 score 是 85,第一个条件(score >= 60)为 True,因此 elif 永远不会被检查。顺序是错的。
解决方案:将条件从最具体到最不具体排序:
# 正确
score = 85
if score >= 80:
print("You got a B!")
elif score >= 60:
print("You passed!")8.5.5) 空的 if 代码块
在 Python 中,你不能有一个空的 if 代码块:
# 错误 - SyntaxError
if temperature > 30:
# 我稍后会在这里添加代码
print("Done")这会产生:
File "example.py", line 3
print("Done")
^
IndentationError: expected an indented block解决方案:使用 pass 语句作为占位符(下一节会介绍):
# 正确 - 使用 pass 作为占位符
if temperature > 30:
pass # TODO: 我稍后会在这里添加代码
print("Done")8.6) 在代码块中使用 pass 作为占位符
有时在写代码时,你知道需要一个 if 语句,但还没决定要在里面写什么。Python 不允许空代码块,所以你需要一种方式来创建一个有效但“什么也不做”的代码块。这就是 pass 语句 (pass statement) 的用途。
8.6.1) pass 是什么?
pass 语句是一个 空操作 (null operation)——当 Python 执行它时,什么都不会发生。它是一个占位符,让你即使还没准备好实现,也能写出语法正确的代码。
if condition:
pass # 暂时什么也不做把 pass 理解为告诉 Python:“我知道这里需要代码,但我以后再补上。”它在开发过程中尤其有用,当你在勾勒程序结构时。
8.6.2) 为什么需要 pass
Python 要求每个代码块中至少有一条语句。空代码块会导致语法错误:
# 错误 - 这会导致错误
if age >= 18:
# TODO: 在这里添加成人逻辑
print("Done")Error:
File "example.py", line 3
print("Done")
^
IndentationError: expected an indented block使用 pass 可以让代码在语法上有效:
# 正确 - 使用 pass 作为占位符
if age >= 18:
pass # TODO: 在这里添加成人逻辑
print("Done")8.6.3) pass 的常见用途
用途 1:开发过程中的占位符
当你在规划程序结构但还没实现全部内容时:
# user_system.py
user_type = input("Enter user type (admin/user/guest): ").lower()
if user_type == "admin":
pass # TODO: 实现 admin 功能
elif user_type == "user":
pass # TODO: 实现 user 功能
elif user_type == "guest":
print("Welcome, guest! Limited access granted.")
else:
print("Invalid user type.")这让你可以运行程序并测试已实现的部分,同时为未来工作保留占位符。
用途 2:在某个分支中有意什么也不做
有时你确实想在某些情况下什么都不做,但又需要处理其他情况:
# positive_numbers.py
# 只处理正数
number = int(input("Enter a number: "))
if number > 0:
result = number * 2
print(f"Double of {number} is {result}")
elif number == 0:
pass # 0 是有效值,但不需要任何操作
else:
print("Negative numbers are not allowed.")8.6.4) 其他场景中的 pass
虽然我们聚焦在 if 语句中的 pass,但随着你学习更多 Python,你也会在其他场景中遇到它:
- 函数 (functions)(第 20 章):用作函数体的占位符
- 类 (classes)(第 31 章):用作类定义的占位符
- 循环 (loops)(第 11-12 章):用作循环体的占位符
- 异常处理器 (exception handlers)(第 29 章):有意忽略错误
现在请记住,当你需要创建一个有效但空的代码块时,pass 就是你的工具。
统整回顾
在本章中,你学习了如何使用条件语句让程序变得更智能、更具响应性。我们来回顾关键概念:
简单 if 语句 只在条件为真时执行代码:
if temperature > 30:
print("It's hot outside!")if-else 语句 在两个备选项之间选择:
if age >= 18:
print("Adult")
else:
print("Minor")if-elif-else 链 处理多个互斥的选项:
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
else:
grade = "F"嵌套 if 语句 在决策中再做决策:
if has_account:
if password_correct:
print("Welcome!")
else:
print("Wrong password")
else:
print("Create an account")需要避免的常见陷阱:
- 在
if、elif、else后缺少冒号 - 缩进错误或缩进不一致
- 用
=代替==进行比较 elif链中顺序错误- 没有
pass的空代码块
pass 语句 可在开发过程中为“空代码块”提供占位符。
你现在已经拥有了根据条件编写智能决策程序的工具。在下一章,我们将学习 布尔逻辑运算符 (boolean logic operators)(and、or、not),它们能让你组合多个条件,从而实现更复杂的决策逻辑。这会让你的 if 语句更强大、更具表达力。