使用结构模式匹配反转测试
Invert a test with structural pattern matching
我一直在将 if-elif-chains 转换为结构模式匹配,但在反向测试中遇到困难。
创建匹配任何受支持模式(文字、class、映射、序列等)的案例很容易。我如何证明否定匹配?
例如,当对象的类型不匹配时,我需要强制对象:
if isinstance(x, (list, dict)):
x = json.dump(x)
elif not isinstance(x, str): # <-- Inverted test
x = str(x)
基本技术
从本质上讲,结构模式匹配的设计仅在存在正匹配时触发案例。但是,有两种解决方法。
最简单的方法是添加 guard 表达式。但这是最后的手段,因为它没有利用模式匹配和解构功能。
第二种方法是添加一个较早的匹配测试,以便后面的情况可以假定反向匹配为真。如果否定案例是最后一个案例,那么这很好用。如果不是,就有点尴尬了,因为需要嵌套。
守卫
进行倒排测试并将其移动到 if-expression:
match x:
case list() | dict():
x = json.dump(x)
case _ if not isinstance(x, str): # <-- Inverted test
x = str(x)
预测试
这里的基本思想是进行正匹配,以便后续案例可以假设为负匹配:
match x:
case list() | dict():
x = json.dump(x)
case str(): # <-- Positive match
pass
case _: # <-- Inverted case
x = str(x)
后续案例的预测试
预测试技术很优雅,除非你有额外的案例要匹配:
if isinstance(x, (list, dict)):
x = json.dump(x)
elif not isinstance(x, str): # <-- Inverted test
x = str(x)
elif x == 'quit': # <-- Additional test
sys.exit(0)
此处最简单的解决方案是将附加测试移到倒置测试之前:
match x:
case list() | dict():
x = json.dump(x)
case 'quit': # <-- Moved the test up
sys.exit(0)
case str(): # <-- Positive match
pass
case _: # <-- Inverted case
x = str(x)
并非总是可以重新排序测试。如果是这样,那么可以引入新的嵌套匹配级别:
case list() | dict():
x = json.dump(x)
case str(): # <-- Positive match
match x: # <-- Nested match
case 'quit': # <-- Inner case
sys.exit(0)
case _: # <-- Inverted case
x = str(x)
我一直在将 if-elif-chains 转换为结构模式匹配,但在反向测试中遇到困难。
创建匹配任何受支持模式(文字、class、映射、序列等)的案例很容易。我如何证明否定匹配?
例如,当对象的类型不匹配时,我需要强制对象:
if isinstance(x, (list, dict)):
x = json.dump(x)
elif not isinstance(x, str): # <-- Inverted test
x = str(x)
基本技术
从本质上讲,结构模式匹配的设计仅在存在正匹配时触发案例。但是,有两种解决方法。
最简单的方法是添加 guard 表达式。但这是最后的手段,因为它没有利用模式匹配和解构功能。
第二种方法是添加一个较早的匹配测试,以便后面的情况可以假定反向匹配为真。如果否定案例是最后一个案例,那么这很好用。如果不是,就有点尴尬了,因为需要嵌套。
守卫
进行倒排测试并将其移动到 if-expression:
match x:
case list() | dict():
x = json.dump(x)
case _ if not isinstance(x, str): # <-- Inverted test
x = str(x)
预测试
这里的基本思想是进行正匹配,以便后续案例可以假设为负匹配:
match x:
case list() | dict():
x = json.dump(x)
case str(): # <-- Positive match
pass
case _: # <-- Inverted case
x = str(x)
后续案例的预测试
预测试技术很优雅,除非你有额外的案例要匹配:
if isinstance(x, (list, dict)):
x = json.dump(x)
elif not isinstance(x, str): # <-- Inverted test
x = str(x)
elif x == 'quit': # <-- Additional test
sys.exit(0)
此处最简单的解决方案是将附加测试移到倒置测试之前:
match x:
case list() | dict():
x = json.dump(x)
case 'quit': # <-- Moved the test up
sys.exit(0)
case str(): # <-- Positive match
pass
case _: # <-- Inverted case
x = str(x)
并非总是可以重新排序测试。如果是这样,那么可以引入新的嵌套匹配级别:
case list() | dict():
x = json.dump(x)
case str(): # <-- Positive match
match x: # <-- Nested match
case 'quit': # <-- Inner case
sys.exit(0)
case _: # <-- Inverted case
x = str(x)