模式匹配

模式 - 图1

廖雪峰
资深软件开发工程师,业余马拉松选手。

当我们用if ... elif ... elif ... else ...判断时,会写很长一串代码,可读性较差。 如果要针对某个变量匹配若干种情况,可以使用match语句。 例如,某个学生的成绩只能是ABC,用if语句编写如下:
  1. score = 'B'
  2. if score == 'A':
  3. print('score is A.')
  4. elif score == 'B':
  5. print('score is B.')
  6. elif score == 'C':
  7. print('score is C.')
  8. else:
  9. print('invalid score.')
如果用match语句改写,则改写如下:
  1. score = 'B'
  2. match score:
  3. case 'A':
  4. print('score is A.')
  5. case 'B':
  6. print('score is B.')
  7. case 'C':
  8. print('score is C.')
  9. case _: # _表示匹配到其他任何情况
  10. print('score is ???.')
使用match语句时,我们依次用case xxx匹配,并且可以在最后(且仅能在最后)加一个case _表示“任意值”,代码较if ... elif ... else ...更易读。

复杂匹配

match语句除了可以匹配简单的单个值外,还可以匹配多个值、匹配一定范围,并且把匹配后的值绑定到变量:

  1. age = 15
  2. match age:
  3. case x if x < 10:
  4. print(f'< 10 years old: {x}')
  5. case 10:
  6. print('10 years old.')
  7. case 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18:
  8. print('11~18 years old.')
  9. case 19:
  10. print('19 years old.')
  11. case _:
  12. print('not sure.')
在上面这个示例中,第一个case x if x < 10表示当age < 10成立时匹配,且赋值给变量x,第二个case 10仅匹配单个值,第三个case 11|12|...|18能匹配多个值,用|分隔。 可见,match语句的case匹配非常灵活。

匹配列表

match语句还可以匹配列表,功能非常强大。

我们假设用户输入了一个命令,用args = ['gcc', 'hello.c']存储,下面的代码演示了如何用match匹配来解析这个列表:
  1. args = ['gcc', 'hello.c', 'world.c']
  2. # args = ['clean']
  3. # args = ['gcc']
  4. match args:
  5. # 如果仅出现gcc,报错:
  6. case ['gcc']:
  7. print('gcc: missing source file(s).')
  8. # 出现gcc,且至少指定了一个文件:
  9. case ['gcc', file1, *files]:
  10. print('gcc compile: ' + file1 + ', ' + ', '.join(files))
  11. # 仅出现clean:
  12. case ['clean']:
  13. print('clean')
  14. case _:
  15. print('invalid command.')
第一个case ['gcc']表示列表仅有'gcc'一个字符串,没有指定文件名,报错; 第二个case ['gcc', file1, *files]表示列表第一个字符串是'gcc',第二个字符串绑定到变量file1,后面的任意个字符串绑定到*files(符号*的作用将在函数的参数中讲解),它实际上表示至少指定一个文件; 第三个case ['clean']表示列表仅有'clean'一个字符串; 最后一个case _表示其他所有情况。 可见,match语句的匹配规则非常灵活,可以写出非常简洁的代码。

参考源码

do_match.py