数据STUDIO

还在使用 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!你觉得怎么样?