Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 634 – 구조적 패턴 매칭: 명세

Author:
Brandt Bucher <brandt at python.org>, Guido van Rossum <guido at python.org>
BDFL-Delegate:

Discussions-To:
Python-Dev list
Status:
Final
Type:
Standards Track
Created:
12-Sep-2020
Python-Version:
3.10
Post-History:
22-Oct-2020, 08-Feb-2021
Replaces:
622
Resolution:
Python-Committers message

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

Important

This PEP is a historical document. The up-to-date, canonical documentation can now be found at The match statement.

×

See PEP 1 for how to propose changes.

초록

이 PEP는 match 문의 기술 명세를 제공합니다. 이 PEP는 PEP 622를 대체하며, 해당 PEP는 이로써 다음 세 부분으로 나뉩니다:

이 PEP에는 의도적으로 논평을 넣지 않았습니다. 동기와 설계 선택에 대한 모든 설명은 PEP 635에 있습니다. 처음 읽는 독자는 PEP 636부터 읽기를 권장합니다. 이 문서는 패턴의 개념, 문법, 의미를 더 쉽게 소개합니다.

문법과 의미

전체 문법은 부록 A를 참조하십시오.

개요와 용어

패턴 매칭 과정은 패턴(case 뒤에 오는 것)과 대상 값(match 뒤에 오는 것)을 입력으로 받습니다. 이 과정을 설명하는 표현으로는 “패턴이 대상 값과 (또는 대상 값에 대해) 매칭된다”와 “패턴을 대상 값에 대해 (또는 대상 값과) 매칭한다” 등이 있습니다.

패턴 매칭의 1차 결과는 성공 또는 실패입니다. 성공한 경우 “패턴이 성공한다”, “매칭이 성공한다” 또는 “패턴이 대상 값과 매칭된다”라고 말할 수 있습니다.

많은 경우 패턴은 하위 패턴을 포함하며, 성공 또는 실패는 그 하위 패턴들을 값에 대해 매칭한 결과(예: OR 패턴의 경우)나 값의 일부분에 대해 매칭한 결과(예: 시퀀스 패턴의 경우)의 성공 또는 실패에 따라 결정됩니다. 이 과정에서는 보통 전체 결과가 결정될 때까지 하위 패턴을 왼쪽에서 오른쪽으로 처리합니다. 예를 들어, OR 패턴은 처음으로 성공하는 하위 패턴에서 성공하고, 시퀀스 패턴은 처음으로 실패하는 하위 패턴에서 실패합니다.

패턴 매칭의 2차 결과로 하나 이상의 이름 바인딩이 생길 수 있습니다. “패턴이 값을 이름에 바인딩한다”라고 말할 수 있습니다. 첫 번째 성공이 나올 때까지 하위 패턴을 시도하는 경우에는 성공한 하위 패턴에 의한 바인딩만 유효합니다. 첫 번째 실패가 나올 때까지 시도하는 경우에는 바인딩이 병합됩니다. 이러한 경우에는 아래에서 설명하는 몇 가지 규칙이 추가로 적용됩니다.

match 문

문법:

match_stmt: "match" subject_expr ':' NEWLINE INDENT case_block+ DEDENT
subject_expr:
    | star_named_expression ',' star_named_expressions?
    | named_expression
case_block: "case" patterns [guard] ':' block
guard: 'if' named_expression

star_named_expression, star_named_expressions, named_expression, block 규칙은 표준 파이썬 문법의 일부입니다.

patterns 규칙은 아래에서 명세합니다.

참고로, match_stmt는 compound_statement의 새로운 대안입니다.:

compound_statement:
    | if_stmt
    ...
    | match_stmt

match와 case 키워드는 소프트 키워드입니다. 즉, 다른 문법적 맥락에서는 예약어가 아닙니다(예상되는 위치에 콜론이 없다면 줄의 시작 부분도 포함합니다). 이는 이 키워드들이 match 문이나 case 블록의 일부일 때만 키워드로 인식되며, 그 밖의 모든 맥락에서는 변수 이름이나 인자 이름으로 사용할 수 있다는 뜻입니다.

매치 의미론

match 문은 먼저 대상 표현식을 평가합니다. 쉼표가 있으면 표준 규칙에 따라 튜플이 만들어집니다.

그런 다음 그 결과로 얻은 대상 값을 사용하여, 패턴이 그 값과의 매칭에 성공하고 동시에 가드 조건이 (있는 경우) “참 같은(truthy)” 첫 번째 case 블록을 선택합니다. 조건을 충족하는 case 블록이 없으면 match 문은 완료됩니다. 그렇지 않으면 선택된 case 블록의 블록이 실행됩니다. 복합문(예: if 문) 안에 중첩된 블록을 실행할 때의 일반적인 규칙이 적용됩니다.

성공한 패턴 매칭 중에 이루어진 이름 바인딩은 실행된 블록이 끝난 뒤에도 유지되며 match 문 이후에 사용할 수 있습니다.

패턴 매칭이 실패하는 과정에서도 일부 하위 패턴은 성공할 수 있습니다. 예를 들어, 패턴 (0, x, 1)을 값 [0, 1, 2]와 매칭하는 동안, 리스트 요소를 왼쪽에서 오른쪽으로 매칭한다면 하위 패턴 x는 성공할 수 있습니다. 구현은 이러한 부분 매칭에 대해 지속되는 바인딩을 만들지 여부를 선택할 수 있습니다. match 문을 포함하는 사용자 코드는 실패한 매칭에 대해 바인딩이 만들어진다는 것에 의존해서는 안 되며, 실패한 매칭으로 인해 변수가 변경되지 않는다고 가정해서도 안 됩니다. 동작의 이 부분은 여러 구현이 최적화를 추가할 수 있도록, 그리고 이 기능의 확장성을 제한할 수 있는 의미론적 제약이 도입되는 것을 막기 위해 의도적으로 명시하지 않은 채로 남겨 두었습니다.

정확한 패턴 바인딩 규칙은 패턴 유형마다 다르며 아래에서 명시합니다.

가드

case 블록에 가드가 있으면, case 블록의 패턴 또는 패턴들이 성공한 뒤에 가드의 표현식이 평가됩니다. 이 평가에서 예외가 발생하면 그 예외는 위로 전파됩니다. 그렇지 않으면, 조건이 “참 같은(truthy)” 경우 해당 case 블록이 선택되고, “거짓 같은(falsy)” 경우 해당 case 블록은 선택되지 않습니다.

가드는 표현식이므로 부작용을 가질 수 있습니다. 가드 평가는 첫 번째 case 블록부터 마지막 case 블록까지 한 번에 하나씩 진행되어야 하며, 패턴이 모두 성공하지는 않은 case 블록은 건너뜁니다. (즉, 해당 패턴들의 성공 여부를 판단하는 일은 순서와 관계없이 일어날 수 있더라도, 가드 평가는 순서대로 이루어져야 합니다.) 가드 평가는 case 블록이 선택되면 중단되어야 합니다.

반박 불가능한 case 블록

문법만으로 패턴이 항상 성공한다는 것을 증명할 수 있으면, 그 패턴은 반박 불가능한(irrefutable) 패턴으로 간주됩니다. 특히, 캡처 패턴과 와일드카드 패턴은 반박 불가능하며, 왼쪽이 반박 불가능한 AS 패턴, 반박 불가능한 패턴을 적어도 하나 포함하는 OR 패턴, 괄호로 묶인 반박 불가능한 패턴도 마찬가지입니다.

case 블록에 가드가 없고 그 패턴이 반박 불가능하면, 해당 case 블록은 반박 불가능한 것으로 간주합니다.

match 문에는 반박 불가능한 case 블록이 최대 하나만 있을 수 있으며, 그 블록은 마지막에 있어야 합니다.

패턴

패턴의 최상위 문법은 다음과 같습니다:

patterns: open_sequence_pattern | pattern
pattern: as_pattern | or_pattern
as_pattern: or_pattern 'as' capture_pattern
or_pattern: '|'.closed_pattern+
closed_pattern:
    | literal_pattern
    | capture_pattern
    | wildcard_pattern
    | value_pattern
    | group_pattern
    | sequence_pattern
    | mapping_pattern
    | class_pattern

AS 패턴

문법:

as_pattern: or_pattern 'as' capture_pattern

(참고: 오른쪽의 이름은 _일 수 없습니다.)

AS 패턴은 as 키워드 왼쪽의 OR 패턴을 대상과 매칭합니다. 이 매칭이 실패하면 AS 패턴은 실패합니다. 그렇지 않으면, AS 패턴은 대상을 as 키워드 오른쪽의 이름에 바인딩하고 성공합니다.

OR 패턴

문법:

or_pattern: '|'.closed_pattern+

두 개 이상의 패턴이 세로 막대(|)로 구분되어 있으면 이를 OR 패턴이라고 합니다. (닫힌 패턴이 하나뿐이면 그냥 닫힌 패턴입니다.)

마지막 하위 패턴만 반박 불가능할 수 있습니다.

각 하위 패턴은 같은 이름 집합을 바인딩해야 합니다.

OR 패턴은 하위 패턴 중 하나가 성공할 때까지 각 하위 패턴을 차례로 대상과 매칭합니다. 그러면 OR 패턴은 성공한 것으로 간주됩니다. 하위 패턴이 하나도 성공하지 않으면 OR 패턴은 실패합니다.

리터럴 패턴

문법:

literal_pattern:
    | signed_number
    | signed_number '+' NUMBER
    | signed_number '-' NUMBER
    | strings
    | 'None'
    | 'True'
    | 'False'
signed_number: NUMBER | '-' NUMBER

규칙 strings와 토큰 NUMBER는 표준 Python 문법에 정의되어 있습니다.

삼중 따옴표 문자열을 지원합니다. 원시 문자열과 바이트 문자열을 지원합니다. F-문자열은 지원하지 않습니다.

signed_number '+' NUMBER 및 signed_number '-' NUMBER 형식은 복소수를 표현할 때만 허용되며, 왼쪽에는 실수가, 오른쪽에는 허수가 와야 합니다.

리터럴 패턴은 다음 비교 규칙에 따라 대상 값이 리터럴이 표현하는 값과 같다고 비교되면 성공합니다:

  • 숫자와 문자열은 == 연산자를 사용하여 비교합니다.
  • 싱글턴 리터럴 None, True, False는 is 연산자를 사용하여 비교합니다.

캡처 패턴

문법:

capture_pattern: !"_" NAME

밑줄 하나(_)는 캡처 패턴이 아닙니다(!"_"가 바로 이것을 표현합니다). 이는 Wildcard Pattern으로 처리됩니다.

캡처 패턴은 항상 성공합니다. 캡처 패턴은 PEP 572에서 월러스 연산자에 대해 정한 이름 바인딩 스코프 규칙에 따라 대상 값을 이름에 바인딩합니다. (요약: 적용되는 nonlocal 또는 global 문이 없으면 그 이름은 그것을 감싸는 가장 가까운 함수 스코프의 지역 변수가 됩니다.)

한 패턴 안에서 같은 이름은 한 번만 바인딩할 수 있습니다. 예를 들어 case x, x: ...는 허용되지 않지만 case [x] | x: ...는 허용됩니다.

와일드카드 패턴

문법:

wildcard_pattern: "_"

와일드카드 패턴은 항상 성공합니다. 와일드카드 패턴은 어떤 이름도 바인딩하지 않습니다.

값 패턴

문법:

value_pattern: attr
attr: name_or_attr '.' NAME
name_or_attr: attr | NAME

패턴의 점으로 구분된 이름은 표준 Python 이름 해석 규칙에 따라 조회됩니다. 그러나 같은 match 문 안에서 같은 값 패턴이 여러 번 나타나면, 인터프리터는 같은 조회를 반복하지 않고 처음 찾은 값을 캐시하여 재사용할 수 있습니다. (분명히 하자면, 이 캐시는 특정 match 문의 특정 실행에만 엄격하게 묶여 있습니다.)

이렇게 찾은 값이 대상 값과 같다고 비교되면(== 연산자 사용) 패턴은 성공합니다.

그룹 패턴

문법:

group_pattern: '(' pattern ')'

(pattern의 문법은 위의 패턴 절을 참조하십시오. 여기에는 쉼표가 포함되지 않는다는 점에 유의하십시오 – 쉼표가 하나 이상 있는 괄호로 묶인 항목의 나열은 ()와 마찬가지로 시퀀스 패턴입니다.)

괄호로 묶인 패턴에는 추가 문법이 없습니다. 이를 통해 사용자는 의도한 그룹화를 강조하기 위해 패턴을 괄호로 감쌀 수 있습니다.

시퀀스 패턴

문법:

sequence_pattern:
  | '[' [maybe_sequence_pattern] ']'
  | '(' [open_sequence_pattern] ')'
open_sequence_pattern: maybe_star_pattern ',' [maybe_sequence_pattern]
maybe_sequence_pattern: ','.maybe_star_pattern+ ','?
maybe_star_pattern: star_pattern | pattern
star_pattern: '*' (capture_pattern | wildcard_pattern)

(뒤에 쉼표가 없는 괄호로 묶인 단일 패턴은 시퀀스 패턴이 아니라 그룹 패턴이라는 점에 유의하십시오. 그러나 [...]로 감싼 단일 패턴은 여전히 시퀀스 패턴입니다.)

[...]를 사용하는 시퀀스 패턴, (...)를 사용하는 시퀀스 패턴, 그리고 열린 시퀀스 패턴 사이에는 의미상의 차이가 없습니다.

시퀀스 패턴은 별표 하위 패턴을 최대 하나까지 포함할 수 있습니다. 별표 하위 패턴은 어느 위치에나 올 수 있습니다. 별표 하위 패턴이 없으면 해당 시퀀스 패턴은 고정 길이 시퀀스 패턴이고, 그렇지 않으면 가변 길이 시퀀스 패턴입니다.

시퀀스 패턴이 성공하려면 대상이 시퀀스여야 하며, 시퀀스라는 것은 대상의 클래스가 다음 중 하나인 것으로 정의됩니다:

  • collections.abc.Sequence를 상속하는 클래스
  • collections.abc.Sequence로 등록된 Python 클래스
  • Py_TPFLAGS_SEQUENCE 비트가 설정된 내장 클래스
  • 위의 것 중 하나를 상속하는 클래스(부모의 Sequence 등록 이전에 정의된 클래스 포함)

다음 표준 라이브러리 클래스는 Py_TPFLAGS_SEQUENCE 비트가 설정됩니다:

  • array.array
  • collections.deque
  • list
  • memoryview
  • range
  • tuple

Note

str, bytes, bytearray는 보통 시퀀스로 간주되지만, 위 목록에 포함되지 않으며 시퀀스 패턴과 일치하지 않습니다.

고정 길이 시퀀스 패턴은 대상 시퀀스의 길이가 하위 패턴의 개수와 같지 않으면 실패합니다.

가변 길이 시퀀스 패턴은 대상 시퀀스의 길이가 별표가 아닌 하위 패턴의 개수보다 작으면 실패합니다.

대상 시퀀스의 길이는 내장 len() 함수로(즉, __len__ 프로토콜을 통해) 구합니다. 다만 인터프리터는 값 패턴에서 설명한 것과 비슷한 방식으로 이 값을 캐시할 수 있습니다.

고정 길이 시퀀스 패턴은 하위 패턴들을 대상 시퀀스의 대응하는 항목들과 왼쪽에서 오른쪽으로 매칭합니다. 하위 패턴 하나가 실패하는 즉시 매칭은 (실패로) 중단됩니다. 모든 하위 패턴이 각자 대응하는 항목과 매칭하는 데 성공하면 시퀀스 패턴은 성공합니다.

가변 길이 시퀀스 패턴은 먼저 고정 길이 시퀀스에서와 마찬가지로, 앞쪽의 별표가 없는 하위 패턴들을 대상 시퀀스의 대응하는 항목들과 매칭합니다. 이것이 성공하면 별표 하위 패턴은 나머지 대상 항목들로 구성된 리스트와 매칭되는데, 이때 별표 하위 패턴 뒤에 오는 별표가 없는 하위 패턴들에 대응하는 항목들은 끝에서 제거됩니다. 그런 다음 나머지 별표가 없는 하위 패턴들이 고정 길이 시퀀스에서와 마찬가지로 대응하는 대상 항목들과 매칭됩니다.

매핑 패턴

문법:

mapping_pattern: '{' [items_pattern] '}'
items_pattern: ','.key_value_pattern+ ','?
key_value_pattern:
    | (literal_pattern | value_pattern) ':' pattern
    | double_star_pattern
double_star_pattern: '**' capture_pattern

(이 문법에서는 **_가 허용되지 않는다는 점에 유의하십시오.)

매핑 패턴은 이중 별표 패턴을 최대 하나까지 포함할 수 있으며, 그 패턴은 반드시 마지막에 와야 합니다.

매핑 패턴은 중복된 키 값을 포함할 수 없습니다. (모든 키 패턴이 리터럴 패턴이면 이는 문법 오류로 간주되며, 그렇지 않으면 런타임 오류로서 ValueError를 발생시킵니다.)

매핑 패턴이 성공하려면 대상이 매핑이어야 하며, 매핑이라는 것은 그 클래스가 다음 중 하나에 해당하는 것으로 정의됩니다:

  • collections.abc.Mapping을 상속하는 클래스
  • collections.abc.Mapping으로 등록된 Python 클래스
  • Py_TPFLAGS_MAPPING 비트가 설정된 내장 클래스
  • 위의 것 중 하나를 상속하는 클래스 (부모의 Mapping 등록 이전에 정의된 클래스 포함)

표준 라이브러리 클래스 dict와 mappingproxy는 Py_TPFLAGS_MAPPING 비트가 설정됩니다.

매핑 패턴에 주어진 모든 키가 대상 매핑에 존재하고, 각 키에 대한 패턴이 대상 매핑의 대응하는 항목과 매칭되면 매핑 패턴은 성공합니다. 키는 항상 == 연산자로 비교됩니다. '**' NAME 형식이 있으면 그 이름은 대상 매핑의 나머지 키-값 쌍을 담은 dict에 바인딩됩니다.

매핑 패턴에서 중복된 키가 감지되면 그 패턴은 유효하지 않은 것으로 간주되며 ValueError가 발생합니다.

키-값 쌍은 대상의 get() 메서드를 인자 두 개를 받는 형식으로 호출하여 매칭됩니다. 따라서 매칭되는 키-값 쌍은 매핑에 이미 존재해야 하며, __missing__이나 __getitem__에 의해 즉석에서 생성되어서는 안 됩니다. 예를 들어 collections.defaultdict 인스턴스는 match 문에 진입할 때 이미 존재하던 키를 가진 패턴에 의해서만 매칭됩니다.

클래스 패턴

문법:

class_pattern:
    | name_or_attr '(' [pattern_arguments ','?] ')'
pattern_arguments:
    | positional_patterns [',' keyword_patterns]
    | keyword_patterns
positional_patterns: ','.pattern+
keyword_patterns: ','.keyword_pattern+
keyword_pattern: NAME '=' pattern

클래스 패턴은 같은 키워드를 여러 번 반복할 수 없습니다.

name_or_attr가 내장 type의 인스턴스가 아니면 TypeError가 발생합니다.

대상이 name_or_attr의 인스턴스가 아니면 클래스 패턴은 실패합니다. 이는 isinstance()를 사용하여 검사합니다.

인자가 없으면 isinstance() 검사가 성공할 때 패턴이 성공합니다. 그렇지 않으면 다음과 같습니다.

  • 키워드 패턴만 있으면 다음과 같이 하나씩 처리합니다.
    • 키워드를 대상의 속성으로 조회합니다.
      • 이때 AttributeError 이외의 예외가 발생하면 그 예외는 위로 전파됩니다.
      • 이때 AttributeError가 발생하면 클래스 패턴은 실패합니다.
      • 그렇지 않으면 키워드에 연결된 하위 패턴을 속성 값과 매칭합니다. 이 매칭이 실패하면 클래스 패턴은 실패합니다. 매칭이 성공하면 다음 키워드로 진행합니다.
    • 모든 키워드 패턴이 성공하면 클래스 패턴 전체가 성공합니다.
  • 위치 패턴이 하나라도 있으면 이를 키워드 패턴으로 변환하고(아래 참조), 구문상의 키워드 패턴(있는 경우)보다 앞에 오는 추가 키워드 패턴으로 취급합니다.

위치 패턴은 name_or_attr가 가리키는 클래스의 __match_args__ 속성을 사용하여 다음과 같이 키워드 패턴으로 변환됩니다.

  • 몇몇 내장 타입(아래에 명시)에서는 대상 전체와 매칭되는 위치 하위 패턴 하나를 허용합니다. (이 경우에도 키워드 패턴은 다른 타입에서와 똑같이 동작합니다.)
  • getattr(cls, "__match_args__", ()))에 해당하는 호출을 수행합니다.
  • 이때 예외가 발생하면 그 예외는 위로 전파됩니다.
  • 반환된 값이 튜플이 아니면 변환은 실패하고 TypeError가 발생합니다.
  • 위치 패턴의 개수가 __match_args__의 길이(len()으로 구한 값)보다 많으면 TypeError가 발생합니다.
  • 그렇지 않으면 위치 패턴 i는 __match_args__[i]를 키워드로 사용하는 키워드 패턴으로 변환됩니다. 단, __match_args__[i]가 문자열이어야 하며, 문자열이 아니면 TypeError가 발생합니다.
  • 중복된 키워드가 있으면 TypeError가 발생합니다.

위치 패턴이 키워드 패턴으로 모두 변환되면, 매칭은 키워드 패턴만 있었던 것처럼 진행됩니다.

앞서 언급했듯이, 다음 내장 타입에서는 위치 하위 패턴을 다르게 처리합니다. 해당 타입은 bool, bytearray, bytes, dict, float, frozenset, int, list, set, str, tuple입니다.

이 동작은 대략 다음과 동등합니다.:

class C:
    __match_args__ = ("__match_self_prop__",)
    @property
    def __match_self_prop__(self):
        return self

부작용과 정의되지 않은 동작

매칭 과정이 명시적으로 일으키는 부작용은 이름 바인딩뿐입니다. 그러나 이 과정은 대상과 그 구성 요소 일부에 대한 속성 접근, 인스턴스 검사, len(), 동등성 비교, 항목 접근에 의존합니다. 또한 값 패턴과 클래스 패턴의 클래스 이름도 평가합니다. 이들 중 어느 것도 보통은 부작용을 일으키지 않지만, 이론적으로는 일으킬 수 있습니다. 이 제안은 어떤 메서드가 호출되는지, 몇 번 호출되는지에 대한 명세를 의도적으로 생략합니다. 따라서 이 동작은 정의되어 있지 않으며, 사용자 코드는 이 동작에 의존해서는 안 됩니다.

또 다른 정의되지 않은 동작은 (같은 case 블록 안에서) 캡처 패턴 뒤에 다른 패턴이 이어지고 그 패턴이 실패하는 경우, 캡처 패턴이 수행하는 변수 바인딩입니다. 이 바인딩은 구현 전략에 따라 더 일찍 또는 더 늦게 일어날 수 있으며, 유일한 제약은 캡처 변수를 명시적으로 사용하는 가드가 평가되기 전에 그 변수가 설정되어 있어야 한다는 점입니다. 가드가 and 절로 이루어진 경우, 왼쪽에서 오른쪽으로의 평가 순서가 유지되는 한 피연산자 평가가 패턴 매칭 사이사이에 끼어들 수도 있습니다.

표준 라이브러리

패턴 매칭을 쉽게 사용할 수 있도록 표준 라이브러리가 다음과 같이 몇 가지 바뀝니다:

  • 네임드튜플과 데이터클래스에는 __match_args__가 자동으로 생성됩니다.
  • 데이터 클래스의 경우 생성된 __match_args__의 속성 순서는 생성된 __init__() 메서드의 해당 인자 순서와 같습니다. 여기에는 속성을 슈퍼클래스에서 상속받는 경우도 포함됩니다. init=False인 필드는 __match_args__에서 제외됩니다.

또한 기존 표준 라이브러리 클래스들을 체계적으로 검토하여, 도움이 된다고 판단되는 곳에 __match_args__를 추가할 것입니다.

부록 A – 전체 문법

다음은 match_stmt의 전체 문법입니다. 이것은 compound_stmt에 추가되는 대안입니다. match와 case는 소프트 키워드라는 점을 기억하십시오. 즉, 다른 문법적 맥락에서는 예약어가 아닙니다(콜론이 와야 할 자리에 콜론이 없다면 줄의 시작 부분에서도 마찬가지입니다). 관례에 따라 하드 키워드는 작은따옴표를, 소프트 키워드는 큰따옴표를 사용합니다.

표준 EBNF 외에 사용되는 기타 표기법:

  • SEP.RULE+는 RULE (SEP RULE)*의 축약형입니다
  • !RULE은 부정 전방 탐색 단언입니다
match_stmt: "match" subject_expr ':' NEWLINE INDENT case_block+ DEDENT
subject_expr:
    | star_named_expression ',' [star_named_expressions]
    | named_expression
case_block: "case" patterns [guard] ':' block
guard: 'if' named_expression

patterns: open_sequence_pattern | pattern
pattern: as_pattern | or_pattern
as_pattern: or_pattern 'as' capture_pattern
or_pattern: '|'.closed_pattern+
closed_pattern:
    | literal_pattern
    | capture_pattern
    | wildcard_pattern
    | value_pattern
    | group_pattern
    | sequence_pattern
    | mapping_pattern
    | class_pattern

literal_pattern:
    | signed_number !('+' | '-')
    | signed_number '+' NUMBER
    | signed_number '-' NUMBER
    | strings
    | 'None'
    | 'True'
    | 'False'
signed_number: NUMBER | '-' NUMBER

capture_pattern: !"_" NAME !('.' | '(' | '=')

wildcard_pattern: "_"

value_pattern: attr !('.' | '(' | '=')
attr: name_or_attr '.' NAME
name_or_attr: attr | NAME

group_pattern: '(' pattern ')'

sequence_pattern:
  | '[' [maybe_sequence_pattern] ']'
  | '(' [open_sequence_pattern] ')'
open_sequence_pattern: maybe_star_pattern ',' [maybe_sequence_pattern]
maybe_sequence_pattern: ','.maybe_star_pattern+ ','?
maybe_star_pattern: star_pattern | pattern
star_pattern: '*' (capture_pattern | wildcard_pattern)

mapping_pattern: '{' [items_pattern] '}'
items_pattern: ','.key_value_pattern+ ','?
key_value_pattern:
    | (literal_pattern | value_pattern) ':' pattern
    | double_star_pattern
double_star_pattern: '**' capture_pattern

class_pattern:
    | name_or_attr '(' [pattern_arguments ','?] ')'
pattern_arguments:
    | positional_patterns [',' keyword_patterns]
    | keyword_patterns
positional_patterns: ','.pattern+
keyword_patterns: ','.keyword_pattern+
keyword_pattern: NAME '=' pattern