還在使用 if-elif 鏈?我告訴你更好的方法
當(dāng)我第一次在 Python 中看到 match-case 時(shí),我就喜歡上使用它了,我以為這只是個(gè)語(yǔ)法糖--—沒(méi)什么值得我改變習(xí)慣的。但后來(lái)我發(fā)現(xiàn),我真的錯(cuò)了。
我發(fā)現(xiàn)這match-case不僅僅是一種更漂亮的書(shū)寫(xiě)方式,而是一種完全不同的思考條件句if-elif-else的方式——一種更清晰、更具表現(xiàn)力,而且說(shuō)實(shí)話……有點(diǎn)意思的方式?
本文中,云朵君將分享我是如何開(kāi)始使用match-case的,有哪些吸引我的地方,以及為什么我現(xiàn)在發(fā)現(xiàn)很難再使用if ...。無(wú)論你是一個(gè)充滿好奇的初學(xué)者,還是一位深陷if…
那么什么是match-case?
Python 3.10 引入了 match 語(yǔ)句,乍一看,它有點(diǎn)像其他語(yǔ)言中的 switch 語(yǔ)句。
但它不止于此。
它旨在使分支邏輯更易讀、更具表現(xiàn)力,并且說(shuō)實(shí)話,編寫(xiě)和維護(hù)起來(lái)更輕松。
下面是基本語(yǔ)法:
match subject:
case pattern1:
# 對(duì) pattern1 執(zhí)行某些操作
case pattern2:
# 對(duì) pattern2 執(zhí)行某些操作
case _:
# 后備/默認(rèn)操作
將 match 視為檢查 subject 的值,并嘗試將其與不同的模式進(jìn)行match。_是一個(gè)通配符——它會(huì)捕獲之前未匹配的任何內(nèi)容。
在下一部分中,我將向你介紹一個(gè)簡(jiǎn)單的實(shí)際用例 — — 這個(gè)用例讓我徹底愛(ài)上了使用這個(gè)方法。
Match-Case實(shí)踐: 處理 HTTP 狀態(tài)代碼
現(xiàn)在,開(kāi)始使用 match-case。假設(shè)我們需要處理 HTTP 狀態(tài)代碼--這是許多網(wǎng)絡(luò)應(yīng)用的常見(jiàn)情況。有了match-case,我們可以簡(jiǎn)化邏輯,使其更具可讀性。
我們可以這樣編寫(xiě)一個(gè)函數(shù)來(lái)處理不同的 HTTP 狀態(tài)代碼:
def handle_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))
在此示例中:
- 如果狀態(tài)代碼是200,返回"Successful Request"
- 如果狀態(tài)代碼是400,返回"Bad Request"
- 如果狀態(tài)代碼是 400,返回"Not Found"
- 如果是其他代碼,則默認(rèn)代碼case _,會(huì)給出 "Invalid Code."
它簡(jiǎn)潔易懂,看起來(lái)像純英語(yǔ)!match-case的美妙之處在于它的清晰度——你可以立即看到每種情況的執(zhí)行情況,而且它比雜亂無(wú)章的"if-elif-else"代碼塊更具可讀性。
使用 OR 運(yùn)算符和 Match-Case
我發(fā)現(xiàn)match-case一個(gè)很酷的功能,可以使用 OR 運(yùn)算符 ( |) 將多個(gè)模式組合在一起。這意味著你可以在一個(gè)案例中匹配多個(gè)可能的值,從而避免編寫(xiě)多行代碼。
下面是一個(gè)我用它來(lái)檢查一個(gè)數(shù)是否為素?cái)?shù)的例子。我不用寫(xiě)一堆case語(yǔ)句,而是可以將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.")
如果輸入的數(shù)字是3、5或7,我們將得到以下輸出:
7 is a prime number.
這是一種處理具有相同結(jié)果的多個(gè)條件的簡(jiǎn)潔方法。無(wú)需一堆elif語(yǔ)句,只需一行簡(jiǎn)潔的|運(yùn)算符即可。
為 Match-Cases添加 if 條件
我非常欣賞match-case的一點(diǎn)是,你可以使用條件為模式添加額外的if邏輯層。你可以在匹配模式的同時(shí),仍然應(yīng)用額外的規(guī)則來(lái)微調(diào)匹配結(jié)果。
例如,假設(shè)我們要將一個(gè)數(shù)字分類為正數(shù)、負(fù)數(shù)或零。通常,你可能會(huì)使用一堆if語(yǔ)句,但使用match-case,你可以更優(yōu)雅地完成它:
def check_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!"
現(xiàn)在,當(dāng)我傳入時(shí)-999,我得到這個(gè)輸出:
Negative number
你可以看到我如何在每個(gè) case 語(yǔ)句中使用if條件。它非常強(qiáng)大,你可以在一個(gè) case 語(yǔ)句中混合使用模式匹配和自定義邏輯。
這意味著你可以匹配更具體的案例,而無(wú)需編寫(xiě)一大堆if檢查。
使用匹配大小寫(xiě)形式的元組
match-case最酷的功能之一就是它與元組配合起來(lái)非常方便。你可以一次匹配多個(gè)值,這對(duì)于二維坐標(biāo)系中存在x與y值的情況來(lái)說(shuō)非常完美。就像一次性解包值一樣!
這是一個(gè)簡(jiǎn)單的例子,我對(duì)二維空間中一個(gè)點(diǎn)的位置進(jìn)行分類:
def point_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"
在這個(gè)例子中,當(dāng)我將點(diǎn)傳遞(8.2, 0)給函數(shù)時(shí),它返回:
on the X-axis
match-case的巧妙在于,你可以直接在元組中匹配值,甚至可以將它們與多個(gè) case 組合(例如 X 軸或 Y 軸上的點(diǎn))。與一堆if語(yǔ)句相比,它使代碼更具可讀性和表達(dá)能力。
匹配列表并提取元素
我喜歡match-case的另一點(diǎn)是它能輕松地處理列表。你不僅可以匹配列表的長(zhǎng)度,還可以提取列表中的特定元素和部分——所有這些都以一種非常簡(jiǎn)潔的方式進(jìn)行。
例如,假設(shè)你需要處理一個(gè)用戶操作列表。你無(wú)需檢查列表長(zhǎng)度并手動(dòng)解包元素,而是可以使用match-case來(lái)自動(dòng)完成:
def process_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.")
在此示例中:
- 如果沒(méi)有執(zhí)行任何操作(空列表),則打印"User has not performed any actions yet."
- 如果只執(zhí)行一個(gè)操作,則會(huì)打印"User performed one action: {action}"
- 如果有多個(gè)動(dòng)作,它會(huì)提取第一個(gè)動(dòng)作并使用*rest語(yǔ)法計(jì)算列表中剩余的動(dòng)作數(shù)。
用一個(gè)示例操作列表來(lái)嘗試一下:
actions = ['login', 'click_button', 'view_item']
process_user_actions(actions)
它將輸出:
First action performed by user: login.
There are 2 more actions.
如你所見(jiàn),match-case從列表中提取元素并進(jìn)行處理變得非常簡(jiǎn)單,無(wú)需手動(dòng)解包或檢查列表長(zhǎng)度。這是一種保持代碼可讀性和可維護(hù)性的好方法!
匹配類實(shí)例和屬性
match-case最強(qiáng)大的功能之一是可以與自定義類及其屬性一起使用。這讓你可以輕松處理對(duì)象的不同實(shí)例或狀態(tài)——幾乎就像直接在代碼中匹配不同"types"的對(duì)象一樣!
下面來(lái)看一個(gè)用于計(jì)算 BMI 的類示例。我用@dataclass它來(lái)簡(jiǎn)化類,然后根據(jù)計(jì)算出的 BMI 進(jìn)行匹配,從而提供個(gè)性化的響應(yīng)。
from dataclasses import dataclass, field
@dataclass
class BMI:
height: float = field(metadata={"unit": "m"})
weight: float = field(metadata={"unit": "kg"})
def calculate_BMI(self):
return self.weight / (self.height ** 2)
# 創(chuàng)建 BMI 實(shí)例
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")
在這個(gè)例子中,我使用calculate_BMI方法計(jì)算BMI ,然后用match-case來(lái)檢查該值并打印出適當(dāng)?shù)南ⅰ?/p>
對(duì)于此輸入:
bmi_instance = BMI(height=1.90, weight=85)
輸出將是:
Optimum range
這種方法非常簡(jiǎn)潔高效——我不需要手動(dòng)編寫(xiě)if語(yǔ)句來(lái)檢查BMI范圍。我只需根據(jù)結(jié)果進(jìn)行匹配并做出相應(yīng)的響應(yīng)即可。
Match-case vs. If-elif-else
假設(shè)你正在創(chuàng)建一個(gè)小程序,根據(jù)你輸入的內(nèi)容告訴你你的星座。你可以使用if-elif-else來(lái)實(shí)現(xiàn):
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,你基本上是逐個(gè)檢查條件。它運(yùn)行良好,但當(dāng)條件很多時(shí)可能會(huì)有點(diǎn)混亂。而且,正如你所見(jiàn),你重復(fù)了多次詞element。
現(xiàn)在,看看如何使用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,代碼更短,更易讀。它更清晰,邏輯也更容易理解。此外,當(dāng)代碼偏離軌道時(shí),默認(rèn)_情況會(huì)自動(dòng)出現(xiàn)。
Match-case優(yōu)點(diǎn)
當(dāng) Python 3.10 引入match-case時(shí),我沒(méi)想到它會(huì)改變我編寫(xiě)代碼的方式。但使用之后,我可以坦誠(chéng)地說(shuō),它讓我的代碼更簡(jiǎn)潔、更直觀。以下是我喜歡它的原因:
1.簡(jiǎn)潔
有了match-case,我只需幾行代碼就能處理復(fù)雜的分支邏輯。我不再需要編寫(xiě)重復(fù)的if-elif-else語(yǔ)句。例如,當(dāng)我檢查多個(gè)條件時(shí),我可以在一行代碼中使用|運(yùn)算符,從而使我的代碼更簡(jiǎn)潔、更清晰。
2.可讀性
它更容易閱讀。有了match-case,邏輯一目了然。每個(gè)情況都截然不同,而且我所檢查的內(nèi)容也一目了然。它比傳統(tǒng)的if-elif-else代碼塊更易讀,尤其是在需要處理多個(gè)條件時(shí)。
3.安全
Match-case幫助我避免錯(cuò)誤。它確保所有情況都得到處理,并且通配符_可以捕獲任何意外情況。我再也不用擔(dān)心遺漏條件或忘記默認(rèn)情況了。
總的來(lái)說(shuō),match-case讓代碼更安全、更易理解、更高效。如果你還沒(méi)試過(guò),我強(qiáng)烈推薦你嘗試一下match-case!你覺(jué)得怎么樣?