来自 Pixabay 的 Kohji Asakawa 的图片
在我的上一篇文章中,我介绍了 Python 3.10 中的所有主要新功能,该版本刚刚发布了两周。其中最重要的功能之一是 Match-Case 语法。
仍然有人认为 Python 不需要“switch-case”语法。甚至 Guido 自己也不支持在 Python 中添加此语法。但是,为什么它仍然发布在这个新版本中呢?在我看来,原因可以在名称中找到。它被称为“match case”,而不是像大多数编程语言一样的“switch case”。
在本文中,我将使用 7 个示例来演示新语法有多灵活和“Pythonic”。希望它能帮助你更容易地理解它。
如果你对 Python 3.10 中的其他功能感兴趣,请参考我的上一篇文章。
Python 3.10 — Five New Features And Considerations
1. 基础
来自 Pixabay 的 Larisa Koshkina 的图片
在任何花哨的东西之前,让我们从这个新语法的基本用法开始。假设我们正在编写一些代码将 HTTP 状态码转换为错误消息,我们可以使用 match-case 语法如下所示。
def http_status(status):
match status:
case 400:
return "Bad request"
case 401:
return "Unauthorized"
case 403:
return "Forbidden"
case 404:
return "Not found"
实际上,对于这个特定的例子,match-case 没有比 if-else 语法带来任何好处,如下所示。
def http_error(status):
if status == 400:
return "Bad request"
elif status == 401:
return "Unauthorized"
elif status == 403:
return "Forbidden"
elif status == 404:
return "Not found"
else:
return "Unknown status code"
如果它只能做这样的事情,我不认为它会被添加。让我们继续看更多的例子,看看它有什么灵活性。
2. 默认情况
来自 Pixabay 的 Bessi 的图片
它的设计目的类似于大多数其他语言中的 switch-case 语法,因此必须有“默认情况”。当没有定义的情况可以匹配时,将执行“默认情况”中的代码。
Python 以其自己的风格实现了这个要求。它利用下划线“_”表示匿名变量。理论基础是匿名变量可以“匹配”任何东西。
让我们看下面的例子。
def http_status(status):
match status:
case 400:
return "Bad request"
case 401:
return "Unauthorized"
case 403:
return "Forbidden"
case 404:
return "Not found"
case _:
return "Other error"
在上面的代码中,我们添加了默认情况并显示“其他错误”。
3. 组合情况
来自 Pixabay 的 DaModernDaVinci 的图片
如果有时我们有多个应该组合的情况怎么办?换句话说,这些是不同的情况,但我们处理它们的方式应该是相同的。
在 Python 中,我们可以使用竖线“|”将这些情况组合成单个情况。它也被认为是“OR”关系。
def http_status(status):
match status:
case 400:
return "Bad request"
case 401 | 403:
return "Authentication error"
case 404:
return "Not found"
case _:
return "Other error"
在上面的代码中,我们认为 401 和 403 错误都是身份验证问题,因此可以在 match-case 中将它们组合起来。
4. 列表中的通配符
来自 Pixabay 的 Frank Winkler 的图片越来越有趣了。假设我们正在使用match-case语法编写闹钟逻辑。它接受一个列表作为参数。第一个元素是一天中的时间。让我们保持简单,所以我们有“早上”,“下午”和“晚上”。第二个元素将是我们需要闹钟提醒我们去做的动作。
但是,我们可能希望闹钟在同一时间提醒我们执行多个动作。因此,我们想要在列表中传递多个操作,以便闹钟可以依次提醒我们执行所有这些操作。
这里是实现这种要求的代码。
def alarm(item):
match item:
case [time, action]:
print(f'Good {time}! It is time to {action}!')
case [time, *actions]:
print('Good morning!')
for action in actions:
print(f'It is time to {action}!')
在此示例中,我们只有两种情况。第一个情况不需要太多解释,因为它只是尝试匹配单个操作。在第二种情况中,我们在变量“actions”前面放了一个星号,因此它可以匹配列表中的一个或多个操作!
让我们试一试。
alarm(['afternoon', 'work'])
alarm(('morning', 'have breakfast', 'brush teeth', 'work'))
#5.子模式
有时,我们可能希望在模式中有模式。具体而言,我们希望匹配情况语句将流程分流到特定的“情况”。但是,在该模式内部,我们希望添加一些其他限制。
记得我们已经定义了“一天中的时间”必须是“早上”,“下午”或“晚上”吗?让我们将此限制添加到match-case代码中。如果“时间”不匹配这3个之一,请告诉用户时间无效。
def alarm(item):
match item:
case [('morning' | 'afternoon' | 'evening'), action]:
print(f'Good (?)! It is time to {action}!')
case _:
print('The time is invalid.')
在上面的代码中,它显示我们可以使用一对括号括起我们要匹配的“模式”,并使用管道分隔这些模式。
如果不匹配给定的3个“时间”之一,则将执行默认情况。
为什么那里有一个问号?我有意添加它,因为我想强调解决方案。通常,很难匹配其中一个子模式,然后引用它确切匹配的模式。但是,在Python中我们可以有这个“参考”。
让我们添加一个“as”关键字,后跟一个变量,这个变量将是参考。
def alarm(item):
match item:
case [('morning' | 'afternoon' | 'evening') as time, action]:
print(f'Good {time}! It is time to {action}!')
case _:
print('The time is invalid.')
#6.条件模式
图片来自[Pixabay](https://pixabay.com/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=585348),由[Michael Mürling]拍摄
我们需要让这个闹钟更加“智能”。当晚上时,让我们显示一些消息以感谢用户完成工作的一天。
def alarm(item):
match item:
case ['evening', action]:
print(f'You almost finished the day! Now {action}!')
case [time, action]:
print(f'Good {time}! It is time to {action}!')
case _:
print('The time is invalid.')
因此,我们在上面的代码中添加了一个新的情况,仅匹配“晚上”。
嗯...第二个似乎有点沮丧。让我们让这个闹钟更加智能,以鼓励用户“工作和生活平衡”。因此,当用户想在晚上工作或学习时,闹钟会建议用户休息一下。(我希望我能有这样的闹钟:D)
def alarm(item):
match item:
case ['evening', action] if action not in ['work', 'study']:
print(f'You almost finished the day! Now {action}!')
case ['evening', _]:
print('Come on, you deserve some rest!')
case [time, action]:
print(f'Good {time}! It is time to {action}!')
case _:
print('The time is invalid.')
为了实现这一点,我们在顶部添加了另一个情况。它带有一个条件。也就是说,当操作是“工作”或“学习”时,显示一些不同的消息。
#7.匹配对象
让我们来看一个更复杂的例子——一个类实例。是的,让我们使用match-case来匹配一个对象。
我将编写一个简单的用例。创建了一个名为“Direction”的类,用于保存水平(东或西)和垂直(北或南)轴上的方向。
class Direction:
def __init__(self, horizontal=None, vertical=None):
self.horizontal = horizontal
self.vertical = vertical
现在,我们想要使用match-case语法来匹配这个类的实例,并根据属性显示消息。
def direction(loc):
match loc:
case Direction(horizontal='east', vertical='north'):
print('You towards northeast')
case Direction(horizontal='east', vertical='south'):
print('You towards southeast')
case Direction(horizontal='west', vertical='north'):
print('You towards northwest')
case Direction(horizontal='west', vertical='south'):
print('You towards southwest')
case Direction(horizontal=None):
print(f'You towards {loc.vertical}')
case Direction(vertical=None):
print(f'You towards {loc.horizontal}')
case _:
print('Invalid Direction')
然后,让我们创建一些对象来测试。
d1 = Direction('east', 'south')
d2 = Direction(vertical='north')
d3 = Direction('centre', 'centre')
结果显示,match-case可以根据它们的属性轻松匹配这些对象!
总结
图片由Markus Kammermann从Pixabay获得
在本文中,我介绍了Python 3.10中引入的新语法“match-case”,以及它的灵活性和强大性。我相信掌握这个新的语法将有助于我们在可读性方面编写更好的代码。
译自:https://towardsdatascience.com/the-match-case-in-python-3-10-is-not-that-simple-f65b350bb025
评论(0)