Python语法糖之match-case
本博客主要参考为北京大学陈斌老师的下一站Python
概述
match-case是python3.10+的新特性,可以理解为python中的switch-case。如果你想要使用它,请注明所需python>=3.10.
基本语法和语义
match <表达式>:
case <值1>:
<语句块1>
case <值2> | <值3> | <值4> :
<语句块2>
case _:
<语句块3>
- 语义:计算表达式的值,依次匹配case后的值,一旦匹配到,就执行对应的语句块1次,语句结束;
- 如果所有case都匹配不上的就执行case _:对应的语句块,语句结束。
- case后必须跟“字面值”,也就是说,不能是表达式。
example1
# match-case的基本例子
color = input("请输入需要查询的颜色:")
match color:
case "red" | "红" | "红色":
r, g, b = 255, 0, 0
case "green" | "绿" | "绿色":
r, g, b = 0, 255, 0
case "yellow" | "黄" | "黄色":
r, g, b = 255, 255, 0
case _:
r, g, b = -1, -1, -1
if r >= 0:
print(f"{color}的颜色代码:#{r:02X}{g:02X}{b:02X}")
else:
print(f"查询不到{color}的颜色代码!")
example2
# 今天是星期几
from datetime import datetime
match datetime.today().weekday():
case 0:
print("今天是星期一")
case 3:
print("疯狂星期四!")
case 4:
print("加油,周末就到了!")
case 5 | 6:
print("周末愉快!")
case _:
print("普普通通的工作日")
进阶用法
如果在case写变量名
- 不是你想象的那样匹配变量的值
case <名字>
的含义是“捕捉”匹配不到的值
p = eval(input("请输入坐标(x,y):"))
match p:
case (0, 0):
print(f"{p}是原点")
case (0, y):
print(f"{p}在Y轴上,距离原点{abs(y)}")
case (x, 0):
print(f"{p}在X轴上,距离原点{abs(x)}")
case (x, y):
print(f"{p}距离原点{abs(x+y*1j)}")
只是为了不写if语句么?
- 引入了match-case语句,我们得到一个C语言里switch语句的等价物
- 可是只是为了把elif语句改一种形式?
- 甚至丢掉了elif判断条件的灵活性
from datetime import datetime
if (w := datetime.today().weekday()) == 0:
print("今天是星期一")
elif w == 3:
print("疯狂星期四!")
elif w == 4:
print("加油,周末就到了!")
elif w in (5, 6):
print("周末愉快!")
else:
print("普普通通的工作日")
匹配列表
match内涵比switch深
- 不光是对于字面值判断相等;
- 对于序列,可以进行“模式匹配”
- 空序列(
[]
),任意长度的序列([ *_ ]
); - 单个占位符(
_
)或者捕捉变量(a
); - 多个占位符(
*_
)或者捕捉变量 (*a
);
- 空序列(
列表的模式匹配
alist = [int(x) for x in input().split()]
print("输入了:", alist)
match alist:
case [ ]:
print("空列表")
case [1, _, third]:
print("这是1开头的三个数,第三个数是:", third)
case [1, *_, last]:
print("这是1开头的列表,最后一个数是:", last)
case [*_, 2]:
print("这是以2结尾的列表!")
case [_, 0, *remains]:
print("这是第二个数为0的列表,0后面是:", remains)
case [*_]:
print("都没匹配上的随便列表。")
示例:摇骰子的统计
# 连续掷三次骰子,分别统计连续三次6、连续两次6、只有一次6的频率
from random import randint
n, triple, double, single = 1000000, 0, 0, 0
for i in range(n):
alist = [randint(1, 6) for k in range(3)]
match alist:
case [6, 6, 6]:
triple += 1
case [6, 6, _] | [_, 6, 6]:
double += 1
case [6, _, _] | [_, 6, _] | [_, _, 6]:
single += 1
print(f"模拟投掷{n:,}次,结果如下:")
print(f"- 连续三次6有{triple:8,d}次,频率为{triple/n*100:4.1f}%")
print(f"- 连续两次6有{double:8,d}次,频率为{double/n*100:4.1f}%")
print(f"- 仅有一次6有{single:8,d}次,频率为{single/n*100:4.1f}%")
匹配字典
字典的模式匹配
- 包含
case
中列明的key:value
模式即可,但key必须是字面值,没有占位符; - 匹配任何字典(
{ }
); - 单个value的占位符(
_
),或者捕捉变量(a
); - 多个key:value的捕捉变量(
**d
),得到一个字典d
;
aset = {"Tom":20, "Jerry":19, "Spike":30, "Tyke":5}
match aset:
#case { }:
# print("匹配到任意字典。")
case { "Tom":201 }:
print("包含了Tom:20")
case { "Tom1":_ }:
print("包含了Tom,value任意。")
case { "Tom1":v }:
print("包含了Tom,捕捉到value=", v)
case { "Tom1":t, "Jerry1":j }:
print("包含Tom和Jerry,对应的value分别是:", t, j)
case { "Tyke1":_, **d }:
print("包含Tyke,其余的key:value是:", d)
case { **d }:
print("匹配到任意字典,并且捕捉到d中:", d)
示例:分组执行任务的表现
# 模拟从工作人员名单中随机抽取派出执行任务
from random import randint, sample
workers = ["Tom", "Jerry", "Spike", "Tyke", "Smith", "Bob"]
n, tom_team, bob_grade, jerry_team, js_grade = 100, 0, 0, 0, 0
for i in range(n):
team = {w: randint(40, 100) for w in sample(workers, 3)}
match team:
case {"Tom": _, "Bob": g}:
tom_team += 1
bob_grade += g
case {"Jerry": g1, "Spike": g2}: # 与上面case互斥
jerry_team += 1
js_grade += (g1 + g2)
print(f"一共派出了{n}次小组,")
print(f"Tom和Bob搭档的次数为{tom_team}")
print(f"--有Tom参与的情况下,Bob的平均业绩为{bob_grade/tom_team:.1f}")
print(f"Jerry和Spike搭档的次数为{jerry_team}")
print(f"--两人搭档的平均业绩为{js_grade/jerry_team/2:.1f}")