还在使用 if-elif 链?我告诉你更好的方法
当我第一次在 Python 中看到 match-case 时,我就喜欢上使用它了,我以为这只是个语法糖--—没什么值得我改变习惯的。但后来我发现,我真的错了。
我发现这match-case不仅仅是一种更漂亮的书写方式,而是一种完全不同的思考条件句if-elif-else的方式——一种更清晰、更具表现力,而且说实话……有点意思的方式?
本文中,云朵君将分享我是如何开始使用match-case的,有哪些吸引我的地方,以及为什么我现在发现很难再使用if ...。无论你是一个充满好奇的初学者,还是一位深陷if…
那么什么是match-case?
Python 3.10 引入了 match 语句,乍一看,它有点像其他语言中的 switch 语句。
但它不止于此。
它旨在使分支逻辑更易读、更具表现力,并且说实话,编写和维护起来更轻松。
下面是基本语法:
match subject:
case pattern1:
# 对 pattern1 执行某些操作
case pattern2:
# 对 pattern2 执行某些操作
case _:
# 后备/默认操作将 match 视为检查 subject 的值,并尝试将其与不同的模式进行match。_是一个通配符——它会捕获之前未匹配的任何内容。
在下一部分中,我将向你介绍一个简单的实际用例 — — 这个用例让我彻底爱上了使用这个方法。
Match-Case实践: 处理 HTTP 状态代码
现在,开始使用 match-case。假设我们需要处理 HTTP 状态代码--这是许多网络应用的常见情况。有了match-case,我们可以简化逻辑,使其更具可读性。
我们可以这样编写一个函数来处理不同的 HTTP 状态代码:
defhandle_http_status(code: int) -> str:
match code:
case 200:
return"Successful Request."
case 400:
return"Bad Request."
case 404:
return"Not Found."
case _:
return"Invalid Code."
status_code = 404
print(handle_http_status(status_code))
在此示例中:
如果状态代码是 200,返回"Successful Request"如果状态代码是 400,返回"Bad Request"如果状态代码是 400,返回"Not Found"如果是其他代码,则默认代码 case _,会给出"Invalid Code."
它简洁易懂,看起来像纯英语!match-case的美妙之处在于它的清晰度——你可以立即看到每种情况的执行情况,而且它比杂乱无章的"if-elif-else"代码块更具可读性。
使用 OR 运算符和 Match-Case
我发现match-case一个很酷的功能,可以使用 OR 运算符 ( |) 将多个模式组合在一起。这意味着你可以在一个案例中匹配多个可能的值,从而避免编写多行代码。
下面是一个我用它来检查一个数是否为素数的例子。我不用写一堆case语句,而是可以将3、5和7组合成一行,如下所示:
number = int(input("Enter a number from 1 to 10: "))
match number:
case 3 | 5 | 7:
print(f"{number} is a prime number.")
case _:
print(f"{number} is not a prime number.")
如果输入的数字是3、5或7,我们将得到以下输出:
7is a prime number.
这是一种处理具有相同结果的多个条件的简洁方法。无需一堆elif语句,只需一行简洁的|运算符即可。
为 Match-Cases添加 if 条件
我非常欣赏match-case的一点是,你可以使用条件为模式添加额外的if逻辑层。你可以在匹配模式的同时,仍然应用额外的规则来微调匹配结果。
例如,假设我们要将一个数字分类为正数、负数或零。通常,你可能会使用一堆if语句,但使用match-case,你可以更优雅地完成它:
defcheck_number(num: float) -> str:
match num:
case x if x > 0:
return"Positive number"
case x if x < 0:
return"Negative number"
case 0:
return"It's zero!"
现在,当我传入时-999,我得到这个输出:
Negative number
你可以看到我如何在每个 case 语句中使用if条件。它非常强大,你可以在一个 case 语句中混合使用模式匹配和自定义逻辑。
这意味着你可以匹配更具体的案例,而无需编写一大堆if检查。
使用匹配大小写形式的元组
match-case最酷的功能之一就是它与元组配合起来非常方便。你可以一次匹配多个值,这对于二维坐标系中存在x与y值的情况来说非常完美。就像一次性解包值一样!
这是一个简单的例子,我对二维空间中一个点的位置进行分类:
defpoint_classification(x: float, y: float) -> str:
match (x, y):
case (0, 0):
return"Origin"
case (0, y):
return"on the Y-axis"
case (x, 0):
return"on the X-axis"
case (x, y):
return"general point"
在这个例子中,当我将点传递(8.2, 0)给函数时,它返回:
on the X-axis
match-case的巧妙在于,你可以直接在元组中匹配值,甚至可以将它们与多个 case 组合(例如 X 轴或 Y 轴上的点)。与一堆if语句相比,它使代码更具可读性和表达能力。
匹配列表并提取元素
我喜欢match-case的另一点是它能轻松地处理列表。你不仅可以匹配列表的长度,还可以提取列表中的特定元素和部分——所有这些都以一种非常简洁的方式进行。
例如,假设你需要处理一个用户操作列表。你无需检查列表长度并手动解包元素,而是可以使用match-case来自动完成:
defprocess_user_actions(actions):
match actions:
case []:
print("User has not performed any actions yet.")
case [action]:
print(f"User performed one action: {action}")
case [action, *rest]:
print(f"""First action performed by user: {action}.
There are {len(rest)} more actions.""")
case _:
print("Unexpected data format.")
在此示例中:
如果没有执行任何操作(空列表),则打印 "User has not performed any actions yet."如果只执行一个操作,则会打印 "User performed one action: {action}"如果有多个动作,它会提取第一个动作并使用 *rest语法计算列表中剩余的动作数。
用一个示例操作列表来尝试一下:
actions = ['login', 'click_button', 'view_item']
process_user_actions(actions)
它将输出:
First action performed by user: login.
There are 2 more actions.
如你所见,match-case从列表中提取元素并进行处理变得非常简单,无需手动解包或检查列表长度。这是一种保持代码可读性和可维护性的好方法!
匹配类实例和属性
match-case最强大的功能之一是可以与自定义类及其属性一起使用。这让你可以轻松处理对象的不同实例或状态——几乎就像直接在代码中匹配不同"types"的对象一样!
下面来看一个用于计算 BMI 的类示例。我用@dataclass它来简化类,然后根据计算出的 BMI 进行匹配,从而提供个性化的响应。
from dataclasses import dataclass, field
@dataclass
classBMI:
height: float = field(metadata={"unit": "m"})
weight: float = field(metadata={"unit": "kg"})
defcalculate_BMI(self):
return self.weight / (self.height ** 2)
# 创建 BMI 实例
bmi_instance = BMI(height=1.90, weight=85)
bmi = bmi_instance.calculate_BMI()
match bmi:
case x if x < 18.5:
print("Underweight")
case x if18.5 <= x <= 24.9:
print("Optimum range")
case _:
print("Overweight")
在这个例子中,我使用calculate_BMI方法计算BMI ,然后用match-case来检查该值并打印出适当的消息。
对于此输入:
bmi_instance = BMI(height=1.90, weight=85)
输出将是:
Optimum range
这种方法非常简洁高效——我不需要手动编写if语句来检查BMI范围。我只需根据结果进行匹配并做出相应的响应即可。
Match-case vs. If-elif-else
假设你正在创建一个小程序,根据你输入的内容告诉你你的星座。你可以使用if-elif-else来实现:
element = input("""Enter your zodiac element (earth, water, fire, air): """).lower()
if element == "earth":
print("You are cultivated and practical.")
elif element == "water":
print("You are emotional and intuitive.")
elif element == "fire":
print("You are brave and passionate.")
elif element == "air":
print("You are social and intellectual.")
else:
print("Bad input.")
使用if-elif-else,你基本上是逐个检查条件。它运行良好,但当条件很多时可能会有点混乱。而且,正如你所见,你重复了多次词element。
现在,看看如何使用match-case做同样的事情:
element = input("""Enter your zodiac element (earth, water, fire, air): """).lower()
match element:
case "earth":
print("You are cultivated and practical.")
case "water":
print("You are emotional and intuitive.")
case "fire":
print("You are brave and passionate.")
case "air":
print("You are social and intellectual.")
case _:
print("Bad input."))
使用match-case,代码更短,更易读。它更清晰,逻辑也更容易理解。此外,当代码偏离轨道时,默认_情况会自动出现。
Match-case优点
当 Python 3.10 引入match-case时,我没想到它会改变我编写代码的方式。但使用之后,我可以坦诚地说,它让我的代码更简洁、更直观。以下是我喜欢它的原因:
1.简洁
有了match-case,我只需几行代码就能处理复杂的分支逻辑。我不再需要编写重复的if-elif-else语句。例如,当我检查多个条件时,我可以在一行代码中使用|运算符,从而使我的代码更简洁、更清晰。
2.可读性
它更容易阅读。有了match-case,逻辑一目了然。每个情况都截然不同,而且我所检查的内容也一目了然。它比传统的if-elif-else代码块更易读,尤其是在需要处理多个条件时。
3.安全
Match-case帮助我避免错误。它确保所有情况都得到处理,并且通配符_可以捕获任何意外情况。我再也不用担心遗漏条件或忘记默认情况了。
总的来说,match-case让代码更安全、更易理解、更高效。如果你还没试过,我强烈推荐你尝试一下match-case!你觉得怎么样?