如何在Python中对含任意索引特定元素的列表使用match case
数学解释器中用Match Case处理除法运算的方案分析与改进
我正在用Python写一个简易数学解释器,先把数学字符串转成数字和运算符组成的列表,再用match case求值。现在想处理除法运算,有两种方案,但都存在问题:
方案一:直接用模式匹配分割列表
代码示例:
c = ['12', '-', '24', '/', '6', '+', '7'] match c: case [*before_div, '/', *after_div]: # 处理除法逻辑 ...
这个模式会匹配所有包含/的列表,但Python的*是贪婪匹配,会把**最后一个/**之前的所有元素分给before_div,之后的分给after_div。如果列表里有多个除法运算符,这会优先处理最右侧的除法,不符合常规数学运算的左结合规则(应该从左到右依次计算)。
方案二:通用匹配后查找索引分割
代码示例:
c = ['12', '-', '24', '/', '6', '+', '7'] match c: case [*_]: try: i = c.index("/") before_div, after_div = c[:i], c[i+1:] # 处理除法逻辑 ... except ValueError: pass
这种方式会找第一个/,符合左结合规则,但用[*_]匹配所有列表后,一旦没有找到/(触发ValueError被捕获),就会直接结束当前case的处理,后续如果有其他运算符的匹配逻辑会被跳过,导致整个解释器无法处理其他运算。
优化方案
如果要符合常规运算逻辑(优先处理第一个出现的除法),可以优化方案二的结构,用带条件的case替代通用匹配,同时结合递归处理子列表:
def eval_list(lst): match lst: # 递归终止条件:只剩一个数字 case [num]: return float(num) # 只处理包含除法的列表 case lst if '/' in lst: i = lst.index('/') # 递归计算除法左右两侧的结果 left_val = eval_list(lst[:i]) right_val = eval_list(lst[i+1:]) # 替换除法部分为计算结果,继续处理剩余列表 new_lst = lst[:i] + [str(left_val / right_val)] + lst[i+1:] return eval_list(new_lst) # 其他运算符的处理逻辑,比如减法、加法 case lst if '-' in lst: i = lst.index('-') left_val = eval_list(lst[:i]) right_val = eval_list(lst[i+1:]) new_lst = lst[:i] + [str(left_val - right_val)] + lst[i+1:] return eval_list(new_lst) case lst if '+' in lst: i = lst.index('+') left_val = eval_list(lst[:i]) right_val = eval_list(lst[i+1:]) new_lst = lst[:i] + [str(left_val + right_val)] + lst[i+1:] return eval_list(new_lst) # 测试 c = ['12', '-', '24', '/', '6', '+', '7'] print(eval_list(c)) # 输出:15.0
这个优化方案的优势:
- 用带条件的case(
case lst if '/' in lst)精准匹配需要处理除法的列表,避免不必要的异常捕获 - 递归处理子列表,符合数学运算的优先级和结合性
- 可以方便扩展其他运算符的处理逻辑,不会出现“未处理任何内容就结束匹配”的问题
如果确实需要用模式匹配处理最后一个除法(比如特殊场景),方案一可以直接使用,但要注意它的贪婪匹配特性。
内容的提问来源于stack exchange,提问作者Yazan Al Hariri
相关产品推荐
相关产品推荐

