Python 3.10 匹配/大小写与常量

问题描述

我尝试用 Python 3.10 中较短的 match/case 替换 if/elif/elif/.../else 代码块。 我定义了三个常量,并希望为每个常量做一些不同的事情,所以我的代码大致如下所示:

>>> const_a = 1
>>> const_b = 2
>>> const_c = 3
>>> interface = const_b  # example
>>> match interface:
...     case const_a:
...             print("case a")
...     case const_b:
...             print("case b")
...     case const_c:
...             print("case c")

但是,运行这段代码时,会出现异常:

File "<stdin>",line 2
SyntaxError: name capture 'const_a' makes remaining patterns unreachable

我做错了什么?

解决方法

match...case 不仅仅是一个 switch...case。来自https://www.python.org/dev/peps/pep-0622/#patterns

  • capture 模式看起来像 x,相当于一个相同的赋值目标:它总是匹配并绑定具有给定(简单)名称的变量。
  • 常量值 模式的工作方式与文字类似,但适用于某些命名常量。请注意,考虑到捕获模式可能存在歧义,它必须是限定(点)名称。它看起来像 Color.RED 并且只匹配等于相应值的值。它永远不会绑定。

因此,您将不得不创建一个将这些变量作为属性并在匹配中使用限定名称的对象

import types

consts = types.SimpleNamespace()
consts.A = 1
consts.B = 2
consts.C = 3

interface = 2

match interface:
    case consts.A:
        print("A")
    case consts.B:
        print("B")
    case consts.C:
        print("C")

正如预期的那样,打印 B

有关为什么的更多信息,请参阅https://www.python.org/dev/peps/pep-0622/#alternatives-for-constant-value-pattern

,

[注意:这个答案完全是假设的]

FWIW,这就是我做匹配/案例的方式 - 对我来说似乎比从头开始获取新变量更直观,并且没有聪明的可能性使用变量来比较或实际常量:

替代匹配/案例提案


""" abstract example to showcase the design """

SOME_CONSTANT = 0
some_string = "qwert"

def example_matchcase (number):
    
    # using an alias/abbreviation with 'as'
    match var as $:
        
        # simple literal case
        case 10:
            print("case 1")
        
        # basic check including another variable
        case len(some_string):
            print("case 2")
        
        # check against a constant
        case SOME_CONSTANT:
            print("case 3")
        
        # if-like statement
        case ?  0 < var < 10:
            print("case 4")
        
        # using the abbreviation
        case ? callable($):
            print("case 5")
        case ? hasattr($,'isnumeric') and $.isnumeric()
            print("case 6")
        
        # slide statement
        case ?  $ < 50:
            print("case 7a")
            slide
        case ?  $ < 25:
            print("case 7b")
            slide
        case ?  $ < 10:
            print("case 7c")
            slide
        
        # alias for improved readability
        case ?  $ in (1,3,5,7)  as early_prime:
            print("case 8 - early prime:",early_prime)
        
        # 'else' instead of 'case _:'
        # more meaningful and avoids confusion with the gettext _
        else:  # or use case $:
            print("unknown value")
            # if you are using returns,you could put a default here


""" real-world example where this would be very elegant """

INTERF_MUPDF = 0
INTERF_PDFIUM = 1
INTERF_POPPLER = 2

def render_thumbnails (interface):
    match interface as $:
        case INTERF_MUPDF:
            from interfaces import InterfMupdf
            _interface = InterfMupdf()
        case INTERF_PDFIUM:
            from interfaces import InterfPdfium
            _interface = InterfPdfium()
        case INTERF_POPPLER:
            from interfaces import InterfPoppler
            _interface = InterfPoppler()
        case ? callable($):
            print("using a custom interface")
            _interface = interface
        else:
            raise Exception("`interface` must be a constant or a callable object")