match 语法是 pyhton 3.10 新加入的 模式匹配 语法,重点是 模式匹配 ,这不是简单的分支匹配。我其实从来都没有用过它,不过之前有小伙伴说起,就去看看。
实战就是学习的捷径,今天我们通过一个文本控制小球移动的小功能,学习 match 语法。
输入 "走 上 下 右 ",回车后,下方小球会按文本指令行动也可以输入 "走 上下右"也可以输入 "走 上-10 下-50-red 右-100" ,控制每一次移动的距离和颜色源码获取回复 "python" 即可
结构匹配程序很简单,打开 main.py ,我们只需要在开始的 create_action 函数中,返回各种 Action.方法调用结果即可。
行8:界面每次输入框中按回车,就会触发此函数行8:参数 input 就是界面输入框的内容比如,直接调用 build_go ,可以控制小球移动:
现在输入任何内容,小球总是往右移动。
这当然不是我们想要的。现在需要加入一些判断,实现 "走 右" 的指令。
最简单就是使用 if 判断:
注意到吗,我们需要先判断文本按空格划分后的列表结构(必须得有2个元素):
这是我认为 python 中使用 match 语法的一个重要场景,结构匹配(序列匹配)。
所以不要拿那种等值匹配的例子与 match 比较,那种场景用字典匹配不香吗
看看 match 模式匹配:
行9: match 关键字,右边是待验证的值,这里直接按空格分隔。也就是待匹配的是一个列表行10: case 表达一次验证,右边是验证表达式。这里的匹配表达式同时做了前面 if 的结构匹配逻辑。也就是说,只有值只有2个元素的情况,并且第一个元素值是 "走",才会进入这个 case 。同时,进行解包,变量 dir 是第二个元素的值。行12:case _ ,通常用于表示不管什么情况,都能匹配,因此一般放到最后。当然,现在不完全等价前面的 if 写法。此时少了两个细节判断,我们一个个来。
怎么判断输入的第一个元素不是 "走" 的情况?既然如果第一个元素是 "走" 的话,自然进入第一个 case,那么只需要下面补充另一个 case 即可捕捉其他情况:
行13-14:注意,仍然需要捕捉2个元素的输入,因此使用 [go,_] 表示两个元素。这里可以使用其他方式表达,比如 (go, _) 或 go, _我们希望在提示信息中显示当前输入的第一个元素,因此定义变量即可捕捉。第二个元素我们不关心,所以用 _但是,怎么判断第二个元素,是 "上" "下" "左" "右" 中的一个?
条件判断case 第一个表达式之后,可以接一个 if 判断:
很直观,其实,上面的 case 相当于做了几个事情:
判断列表得有2个元素解包各个元素,并判断第一个元素必须是 "走"。第二个元素到 dir 变量判断 dir 变量值但是,现在如果输入 "走 x" ,无法提示第二个方向输入错误。因此,还要补一个 case:
当然你也可以在第一个 case 里面加判断
现在可以看到 match 的特点:
越是具体的匹配(限制条件),越是靠上避免了嵌套的判断不过,上面的代码判断次数上,其实是不等价于 文章开篇的 if 写法。也就是说,其实每个 case 都重复做了 解包、判断长度、判断值等一系列操作。
所以说,用 if 也可以写出一样的整体结构,只不过每个判断结构中的语法没有 match 简洁。
继续完成后续的功能,看看 match 还提供了什么特殊能力。
不定个数匹配现在只能支持一个方向,太麻烦了,希望 "走 上 下 左 右" ,小球可以按顺序执行行动。那就是说,不仅仅是2个元素,而是:
第一个元素必须是 "走"后面可以无数个元素。但有限制 "必须合法的方向"行10: case 模式中,第二个元素 *dirs ,就与 python 的解包规则一样,从第二个元素开始,后续所有元素都被收集成一个列表,放到 dirs 变量中行11:返回多个指令现在效果是可以了,但每次输入方向时,每个方向之间需要空格分开,太麻烦了,如果可以直接输入 "走 上下左右" 就好了。
你可能会想,python 中其实字符串就是单个字符的集合,比如下面的代码是成立的:
此时应该总是会走第一个 case 吧。实际上 match 不会做这种隐式转换。如果输入 "走 上下左右" ,会进入第二个 case:
or 模式case 模式匹配中,可以指定多个匹配模式:
行10:使用 | 可以同时定义多个匹配规则,只要其中一个规则匹配,则会走右边的 if 。注意,多个规则中使用的变量必须相同。也就是,此时变量 dirs 可能是 str 或 str 列表。从智能提示就可以看出来:
现在 "走" 开始的指令已经可以了。但总是需要先输入 "走" ,太麻烦了,如果直接输入 "上下左右" ,就应该识别出来是 "走" 指令啊。
简单:
目前为止,我们一直在匹配列表(输入内容按空格分隔)。在 match 语法的使用场景中,对字典的匹配,也是我认为的一个重要场景。
上面的例子代码,在 main.py 文件中。字典匹配的实现在 main_by_dict_match.py
字典匹配我们把解析流程修改一下:
专门有函数负责第一层解析,返回一个字典。字典总有一个 action 键值对,表示具体指令。比如 "走"、"还原" 等针对不同的命令,字典有不同的键值对解析成字典的函数,问人工智能"好朋友"就可以了:
用到的都是前面的知识单独实现函数的好处是,很容易测试和定位问题:
有了命令信息字典,现在看看怎么使用 match 对字典匹配:
行10:match 右边填入字典行11:字典的匹配模式很简单,只要字典中包含列出的键值对,就通过(还需要通过右边的 if 判断)。这里,只要字典有 action 和 cmds 的 key,并且 action 值是 "走" ,即可匹配。后面的 if 判断进一步验证里面的 cmds场景每个新语法,都是为了解决某种场景而设计。从这个案例中可以看到,我们不必把所有处理逻辑集中到一个 match 中。而是适当把逻辑拆分一下。
对于非结构匹配需求,我认为没太多必要使用 match 。而是可以考虑使用字典匹配。
match 最大的限制在于, case 表达式是固定的,无法在程序运行的时候动态改变。因此它适合用在固定模式的匹配上。
不要忘记一键三连。你的点赞、收藏、关注,是我创作的动力。