Python 3.10 совпадение / регистр с константами

Я попытался заменить блок кода if / elif / elif/.../else на более короткий match/caseиз Python 3.10. У меня определены три константы, и я хочу сделать для каждой что-то свое, поэтому мой код выглядит примерно так:

      >>> 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

Что я делаю неправильно?

2 ответа

Решение

В match...case это больше, чем просто switch...case. Из https://www.python.org/dev/peps/pep-0622/#patterns :

  • А захват картина выглядит как х и эквивалентен идентичной цель назначения: она всегда соответствует и связывает переменную с заданным (простым) именем.
  • Постоянное значение шаблон работает как буквальный , но и для некоторых именованных констант. Обратите внимание, что это должно быть полное имя (с точками), учитывая возможную двусмысленность с шаблоном захвата. Он выглядит как 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")

Другие вопросы по тегам