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