避免结构模式匹配中的意外捕获

Ray*_*ger 7 python defensive-programming python-3.10 structural-pattern-matching

这个例子在使用模式匹配时被讨论为可能的“陷阱”:

NOT_FOUND = 400

retcode = 200
match retcode:
    case NOT_FOUND:
        print('not found')  

print(f'Current value of {NOT_FOUND=}')
Run Code Online (Sandbox Code Playgroud)

这是使用结构模式匹配意外捕获的示例。它给出了这个意想不到的输出:

not found
Current value of NOT_FOUND=200
Run Code Online (Sandbox Code Playgroud)

同样的问题以其他形式出现:

match x:
    case int():
        pass
    case float() | Decimal():
        x = round(x)
    case str:
        x = int(x)
Run Code Online (Sandbox Code Playgroud)

在这个例子中,str需要有括号,str(). 没有它们,它“捕获”并且str内置类型被替换为x的值。

是否有防御性编程实践可以帮助避免这些问题并提供早期检测?

Ray*_*ger 10

最佳实践

是否有一种防御性编程实践可以帮助避免这些问题并提供早期检测?

是的。通过始终包含 PEP 634 所描述的无可辩驳的 case 块,可以轻松检测到意外捕获。

用简单的语言来说,这意味着始终匹配的包罗万象的情况。

怎么运行的

意外捕获总是匹配的。不允许超过一个无可辩驳的案例块。因此,当添加有意的包罗万象时,会立即检测到意外捕获。

修复第一个示例

只需在末尾添加一个包罗万象的通配符模式即可:

match retcode:
    case NOT_FOUND:
        print('not found')
    case _:
        pass
Run Code Online (Sandbox Code Playgroud)

这会立即检测到问题并给出以下错误:

SyntaxError: name capture 'NOT_FOUND' makes remaining patterns unreachable
Run Code Online (Sandbox Code Playgroud)

修复第二个示例

在末尾添加一个包罗万象的通配符模式:

match x:
    case int():
        pass
    case float() | Decimal():
        x = round(x)
    case str:
        x = int(x)
    case _:
        pass
Run Code Online (Sandbox Code Playgroud)

同样,问题立即被检测到:

SyntaxError: name capture 'str' makes remaining patterns unreachable
Run Code Online (Sandbox Code Playgroud)