简体   繁体   English

使用结构模式匹配反转测试

[英]Invert a test with structural pattern matching

I've been converting if-elif-chains to structural pattern matching but am having difficulty with inverted tests.我一直在将 if-elif-chains 转换为结构模式匹配,但在反向测试中遇到困难。

It is easy to make cases that match any of the supported patterns (literal, class, mapping, sequence, etc).很容易创建匹配任何受支持模式(文字、class、映射、序列等)的案例。 How do I make a case for a negative match?我如何提出否定匹配的理由?

For example, I need to coerce an object when its type doesn't match:例如,当类型匹配时,我需要强制转换为 object:

   if isinstance(x, (list, dict)):
      x = json.dump(x)  
   elif not isinstance(x, str):    # <-- Inverted test
      x = str(x)

Basic technique基本技术

Intrinsically, the design of structural pattern matching only triggers a case when there is a positive match.本质上,结构模式匹配的设计仅在存在正匹配时触发案例。 However, there are two workarounds.但是,有两种解决方法。

The easiest way is to add a guard expression.最简单的方法是添加一个保护表达式。 But this is a last resort because it doesn't take advantage of the pattern matching and destructuring capabilities.但这是最后的手段,因为它没有利用模式匹配和解构功能。

The second way is to add an earlier matching test so that later cases can presume that the inverse match is true.第二种方法是添加一个较早的匹配测试,以便后面的情况可以假定反向匹配为真。 This works nicely if the negative case was intended to be the last case.如果否定案例是最后一个案例,那么这很好用。 If not, it becomes a little awkward because nesting is required.如果不是,它会变得有点尴尬,因为需要嵌套。

Guards卫兵

Take the inverted test and move it into an if-expression:进行倒置测试并将其移动到 if 表达式中:

   match x:
       case list() | dict():
           x = json.dump(x)
       case _ if not isinstance(x, str):    # <-- Inverted test
           x = str(x)

Pretest预测试

The basic idea here is to make a positive match so that subsequent cases can assume a negative match:这里的基本思想是进行正匹配,以便后续案例可以假设为负匹配:

   match x:
       case list() | dict():
           x = json.dump(x)
       case str():                          # <-- Positive match
           pass
       case _:                              # <-- Inverted case
           x = str(x)

Pretest with subsequent cases对后续案例进行预测试

The pretest technique is elegant unless you there are additional cases to be matched:预测试技术很优雅,除非您有其他情况需要匹配:

   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)

The easiest solution here is to to move the additional test to occur before the inverted test:这里最简单的解决方案是将附加测试移动到倒置测试之前:

   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)

It's not always possible to reorder the tests.重新排序测试并不总是可能的。 If so, then a new level of nested matching can be introduced:如果是这样,则可以引入新级别的嵌套匹配:

   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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM