8. 複合文 (compound statement)

複合文には、他の文 (のグループ) が入ります; 複合文は、中に入っている他の文の実行の制御に何らかのやり方で影響を及ぼします。一般的には、複合文は複数行にまたがって書かれますが、全部の文を一行に連ねた単純な書き方もあります。

ifwhile 、および for 文は、伝統的な制御フロー構成を実現します。 try は例外処理および/または一連の文に対するクリーンアップコードを指定します。それに対して、 with 文はコードのかたまりの前後でコードの初期化と終了処理を実行できるようにします。関数とクラス定義もまた、構文的には複合文です。

複合文は、一つ以上の '節 (clause)' からなります。節は、ヘッダと 'スイート (suite)' からなります。一つの複合文を成す各節のヘッダは、全て同じインデントレベルに置かれます。各節のヘッダは一意に識別するキーワードで始まり、コロンで終わります。スイートは、節によって制御される文の集まりです。スイートは、ヘッダがある行のコロンの後にセミコロンで区切って置かれた一つ以上の単純文、または、ヘッダに続く行で一つ多くインデントされた文の集まりです。後者の形式のスイートに限り、さらに複合文をネストできます; 以下の文は、 else 節がどちらの if 節に属するかがはっきりしないなどの理由から不正になります:

if test1: if test2: print(x)

また、このコンテキスト中では、セミコロンによる結合はコロンより強いです。従って、以下の例では、 print() の呼び出しはは全て実行されるか、全く実行されないかのどちらかです:

if x < y < z: print(x); print(y); print(z)

まとめると、以下のようになります:

compound_stmt ::=  if_stmt
                   | while_stmt
                   | for_stmt
                   | try_stmt
                   | with_stmt
                   | match_stmt
                   | funcdef
                   | classdef
                   | async_with_stmt
                   | async_for_stmt
                   | async_funcdef
suite         ::=  stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT
statement     ::=  stmt_list NEWLINE | compound_stmt
stmt_list     ::=  simple_stmt (";" simple_stmt)* [";"]

なお、文は常に NEWLINE か、その後に DEDENT が続いたもので終了します。また、オプションの継続節は必ず、文を開始できない予約語で始まるので、曖昧さは存在しません。 (Python では、 'ぶら下がり (dangling) else' 問題は、ネストされた if 文をインデントさせることで解決されます)。

以下の節における文法規則の記述方式は、明確さのために、各節を別々の行に書くようにしています。

8.1. if

if 文は、条件分岐を実行するために使われます:

if_stmt ::=  "if" assignment_expression ":" suite
             ("elif" assignment_expression ":" suite)*
             ["else" ":" suite]

if 文は、式を一つ一つ評価してゆき、真になるまで続けて、真になった節のスイートだけを選択します (真: true と偽: false の定義については、 ブール演算 (boolean operation) 節を参照してください); 次に、選択したスイートを実行します (そして、 if 文の他の部分は、実行や評価をされません)。全ての式が偽になった場合、 else 節があれば、そのスイートが実行されます。

8.2. while

while 文は、式の値が真である間、実行を繰り返すために使われます:

while_stmt ::=  "while" assignment_expression ":" suite
                ["else" ":" suite]

while 文は式を繰り返し真偽評価し、真であれば最初のスイートを実行します。式が偽であれば (最初から偽になっていることもありえます)、 else 節がある場合にはそれを実行し、ループを終了します。

最初のスイート内で break 文が実行されると、 else 節のスイートを実行することなくループを終了します。 continue 文が最初のスイート内で実行されると、スイート内にある残りの文の実行をスキップして、式の真偽評価に戻ります。

8.3. for

for 文は、シーケンス (文字列、タプルまたはリスト) や、その他の反復可能なオブジェクト (iterable object) 内の要素に渡って反復処理を行うために使われます:

for_stmt ::=  "for" target_list "in" starred_list ":" suite
              ["else" ":" suite]

starred_list 式は一度だけ評価され、評価結果として イテラブル オブジェクトを返す必要があります。そのイテラブルから イテレータ が作られます。まず、イテレータから生成される最初の要素が、通常の代入式のルールに従って target_list に代入され(代入文 (assignment statement) 節参照)、1つ目のスイート (suite) が実行されます。これが、イテレータから生成される各要素に対して繰り返されます。イテレータのすべての要素が処理されたあと、 else 節がもしあれば実行され、ループ処理が終了します。

最初のスイートの中で break 文が実行されると、 else 節のスイートを実行することなくループを終了します。 continue 文が最初のスイート内で実行されると、スイート内にある残りの文の実行をスキップして、次の要素の処理に移るか、これ以上次の要素が無い場合は else 節の処理に移ります。

for ループはターゲットリスト内の変数への代入を行います。 これにより、for ループ内も含めて、それ以前の全ての代入は上書きされます:

for i in range(10):
    print(i)
    i = 5             # this will not affect the for-loop
                      # because i will be overwritten with the next
                      # index in the range

ループが終了してもターゲットリスト内の名前は削除されませんが、イテラブルが空の場合には、ループでの代入は全く行われません。ヒント: 組み込み型 range() は、 整数の不変算術列を表します。例えば、 range(3) を反復すると0、1そして2の順に結果を返します。

バージョン 3.11 で変更: 式のリストの中でアスタリスク付きの式 (starred elements) を指定できるようになりました。

8.4. try

try 文は、ひとまとめの文に対して、例外処理および/またはクリーンアップコードを指定します:

try_stmt  ::=  try1_stmt | try2_stmt | try3_stmt
try1_stmt ::=  "try" ":" suite
               ("except" [expression ["as" identifier]] ":" suite)+
               ["else" ":" suite]
               ["finally" ":" suite]
try2_stmt ::=  "try" ":" suite
               ("except" "*" expression ["as" identifier] ":" suite)+
               ["else" ":" suite]
               ["finally" ":" suite]
try3_stmt ::=  "try" ":" suite
               "finally" ":" suite

例外に関するその他の情報は 例外 節にあります。また、 raise 文の使用による例外の生成に関する情報は、 raise 文 節にあります。

8.4.1. except

except 節は一つ以上の例外ハンドラを指定します。 try 節内で例外が起きなければ、どの例外ハンドラも実行されません。 try スイート内で例外が発生すると、例外ハンドラの検索が開始されます。この検索では、except 節を逐次、発生した例外に対応するまで調べます。式を伴わない except 節を使うなら、最後に書かなければならず、これは全ての例外に対応します。式を伴う except 節に対しては、その式が評価され、結果のオブジェクトが例外と "互換である (compatible)" 場合にその節が対応します。ある例外に対してオブジェクトが互換であるのは、そのオブジェクトが例外オブジェクトのクラスかその 非仮想基底クラス の場合、または例外オブジェクトのクラスかその非仮想基底クラスの要素が入ったタプルである場合です。

例外がどの except 節にも合致しなかった場合、現在のコードを囲うさらに外側、そして呼び出しスタックへと検索を続けます。 [1]

except 節のヘッダにある式を値評価するときに例外が発生すると、元々のハンドラ検索はキャンセルされ、新たな例外に対する例外ハンドラの検索を現在の except 節の外側のコードや呼び出しスタックに対して行います (try 文全体が例外を発行したかのように扱われます)。

対応する except 節が見つかると、except 節のスイートが実行されます。その際、 as キーワードが except 節に存在すれば、その後で指定されているターゲットに例外が代入されます。全ての except 節は実行可能なブロックを持っていなければなりません。このブロックの末尾に到達すると、通常は try 文全体の直後から実行を継続します。(このことは、ネストされた二つの例外ハンドラが同じ例外に対して存在し、内側のハンドラ内の try 節で例外が発生した場合、外側のハンドラはその例外を処理しないことを意味します。)

例外が as target を使って代入されたとき、それは except 節の終わりに消去されます。これはちょうど、以下のコード:

except E as N:
    foo

が、以下のコードに翻訳されたかのようなものです:

except E as N:
    try:
        foo
    finally:
        del N

よって、例外を except 節以降で参照できるようにするためには、別の名前に代入されなければなりません。例外が削除されるのは、トレースバックが付与されると、そのスタックフレームと循環参照を形作り、次のガベージ収集までそのフレーム内のすべての局所変数を生存させてしまうからです。

except 節のスイートが実行される前に、例外が sys モジュールに格納されます。 except 節の中では、 sys.exception() を呼び出す事によってこの例外にアクセスすることができます。 例外ハンドラを抜けると、 sys モジュールに格納されている例外の値が、一つ前の値に戻ります:

>>> print(sys.exception())
None
>>> try:
...     raise TypeError
... except:
...     print(repr(sys.exception()))
...     try:
...          raise ValueError
...     except:
...         print(repr(sys.exception()))
...     print(repr(sys.exception()))
...
TypeError()
ValueError()
TypeError()
>>> print(sys.exception())
None

8.4.2. except*

The except* clause(s) are used for handling ExceptionGroups. The exception type for matching is interpreted as in the case of except, but in the case of exception groups we can have partial matches when the type matches some of the exceptions in the group. This means that multiple except* clauses can execute, each handling part of the exception group. Each clause executes at most once and handles an exception group of all matching exceptions. Each exception in the group is handled by at most one except* clause, the first that matches it.

>>> try:
...     raise ExceptionGroup("eg",
...         [ValueError(1), TypeError(2), OSError(3), OSError(4)])
... except* TypeError as e:
...     print(f'caught {type(e)} with nested {e.exceptions}')
... except* OSError as e:
...     print(f'caught {type(e)} with nested {e.exceptions}')
...
caught <class 'ExceptionGroup'> with nested (TypeError(2),)
caught <class 'ExceptionGroup'> with nested (OSError(3), OSError(4))
  + Exception Group Traceback (most recent call last):
  |   File "<stdin>", line 2, in <module>
  | ExceptionGroup: eg
  +-+---------------- 1 ----------------
    | ValueError: 1
    +------------------------------------

Any remaining exceptions that were not handled by any except* clause are re-raised at the end, along with all exceptions that were raised from within the except* clauses. If this list contains more than one exception to reraise, they are combined into an exception group.

If the raised exception is not an exception group and its type matches one of the except* clauses, it is caught and wrapped by an exception group with an empty message string.

>>> try:
...     raise BlockingIOError
... except* BlockingIOError as e:
...     print(repr(e))
...
ExceptionGroup('', (BlockingIOError()))

An except* clause must have a matching type, and this type cannot be a subclass of BaseExceptionGroup. It is not possible to mix except and except* in the same try. break, continue and return cannot appear in an except* clause.

8.4.3. else

オプションの else 節は、コントロールフローが try スイートを抜け、例外が送出されず、 return 文、 continue 文、 break 文のいずれもが実行されなかった場合に実行されます。 else 節で起きた例外は、手前にある except 節では処理されません。

8.4.4. finally

finally 節がある場合は、 '後始末' の対処を指定します。まず except 節や else 節を含め、 try 節が実行されます。それらの節の中で例外が起き、その例外が処理されていない場合には、例外は一時的に保存されます。次に finally 節が実行されます。保存された例外があった場合は、 finally 節の末尾で再送出されます。 finally 節で別の例外が送出される場合は、保存されていた例外は新しい例外のコンテキストとして設定されます。 finally 節で return 文、 break 文あるいは continue 文を実行した場合は、保存された例外は破棄されます:

>>> def f():
...     try:
...         1/0
...     finally:
...         return 42
...
>>> f()
42

finally 節を実行している間は、プログラムからは例外情報は利用できません。

try...finally 文の try スイート内で returnbreak 、または continue 文が実行された場合、 finally 節も、この文を '抜け出る途中に' 実行されます。

関数の返り値は最後に実行された return 文によって決まります。 finally 節は必ず実行されるため、finally 節で実行された return 文は常に最後に実行されることになります:

>>> def foo():
...     try:
...         return 'try'
...     finally:
...         return 'finally'
...
>>> foo()
'finally'

バージョン 3.8 で変更: Python3.8 以前では、実装上の問題により finally 節での continue 文は不正でした。

8.5. with

with 文は、ブロックの実行を、コンテキストマネージャによって定義されたメソッドでラップするために使われます (with文とコンテキストマネージャ セクションを参照してください)。これにより、よくある try...except...finally 利用パターンをカプセル化して便利に再利用することができます。

with_stmt          ::=  "with" ( "(" with_stmt_contents ","? ")" | with_stmt_contents ) ":" suite
with_stmt_contents ::=  with_item ("," with_item)*
with_item          ::=  expression ["as" target]

一つの "要素" を持つ with 文の実行は以下のように進行します:

  1. コンテキスト式 (with_item で与えられた式) を評価することで、コンテキストマネージャを取得します。

  2. コンテキストマネージャの __enter__() メソッドが、後で使うためにロードされます。

  3. コンテキストマネージャの __exit__() メソッドが、後で使うためにロードされます。

  4. コンテキストマネージャの __enter__() メソッドが呼ばれます。

  5. with 文にターゲットが含まれていたら、それに __enter__() からの戻り値が代入されます。

    注釈

    with 文は、 __enter__() メソッドがエラーなく終了した場合には __exit__() が常に呼ばれることを保証します。ですので、もしターゲットリストへの代入中にエラーが発生した場合には、これはそのスイートの中で発生したエラーと同じように扱われます。以下のステップ 7 を参照してください。

  6. スイートが実行されます。

  7. コンテキストマネージャの __exit__() メソッドが呼ばれます。スイートが例外によって終了されたのなら、その例外の型、値、トレースバックが __exit__() に引数として渡されます。そうでなければ、 3 つの None 引数が与えられます。

    スイートが例外により終了され、 __exit__() メソッドからの戻り値が偽(false)ならば、例外が再送出されます。この戻り値が真(true)ならば例外は抑制され、実行は with 文の次の文から続きます。

    もしそのスイートが例外でない何らかの理由で終了した場合、その __exit__() からの戻り値は無視されて、実行は発生した終了の種類に応じた通常の位置から継続します。

以下のコード:

with EXPRESSION as TARGET:
    SUITE

これは次と等価です:

manager = (EXPRESSION)
enter = type(manager).__enter__
exit = type(manager).__exit__
value = enter(manager)
hit_except = False

try:
    TARGET = value
    SUITE
except:
    hit_except = True
    if not exit(manager, *sys.exc_info()):
        raise
finally:
    if not hit_except:
        exit(manager, None, None, None)

複数の要素があるとき、コンテキストマネージャは複数の with 文がネストされたかのように進行します:

with A() as a, B() as b:
    SUITE

これは次と等価です:

with A() as a:
    with B() as b:
        SUITE

括弧で囲むことにより、複数のコンテキストマネージャを複数行に渡って書くことができます。 例:

with (
    A() as a,
    B() as b,
):
    SUITE

バージョン 3.1 で変更: 複数のコンテキスト式をサポートしました。

バージョン 3.10 で変更: 括弧で囲むことで、文を複数行に分割して書けるようになりました。

参考

PEP 343 - "with" ステートメント

Python の with 文の仕様、背景、および例が記載されています。

8.6. match

Added in version 3.10.

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

注釈

このセクションでは、一重引用符で囲まれているものは ソフトキーワード を表します。

パターンマッチングは、パターン (case の後ろ) とマッチング対象の値 (match の後ろ)を入力とします。 パターン (サブパターンを含みうる) は、マッチング対象の値に対して、マッチするかどうかの判定が行われます。結果として次のことが起こります:

  • マッチ成功、もしくはマッチ失敗 (パターン成功・失敗とも呼ばれます)。

  • マッチした値の名前への束縛。必要な条件は後述します。

matchcase キーワードは ソフトキーワード です。

参考

  • PEP 634 -- 構造的パターンマッチ: 仕様

  • PEP 636 -- 構造的パターンマッチ: チュートリアル

8.6.1. 概要

match 文の論理的な動作の流れの概要は次の通りです:

  1. サブジェクト式 subject_expr が評価され、サブジェクト値が得られます。 サブジェクト式がコンマを含む場合、 通常のルール に従ってタプルが作成されます。

  2. case_block 内の各パターンに対して、サブジェクト値がマッチするかどうかをチェックします。 マッチ成功・失敗の具体的なルールは後述します。 マッチングのチェックにより、パターン内の名前の一部あるいはすべてに値が束縛されます。 具体的な束縛ルールはパターンの種類によって異なるため、後述します。 マッチが成功したパターンの中で束縛された名前は、そのパターンのブロック内だけでなく、 match 文の後でも使用することができます

    注釈

    パターンマッチが全体として失敗しても、その中に含まれるサブパターンが成功する可能性があります。 失敗したマッチで発生する名前束縛を前提としたコードを書かないように気をつけてください。 逆に、マッチが失敗したあとで変数の値が変わっていないというのも前提にしないでください。 実際どういう振る舞いになるかは Python の実装依存であり、実装間で異なる可能性があります。 色々な実装が最適化を行えるよう、意図的に実装依存としています。

  3. パターンが成功した場合、該当のガードが (もしあれば) 評価されます。 この場合、パターン内の名前がすべて束縛されていることが保証されています。

    • ガードの評価値が真であるか、もしくはガードがなければ、 case_block 内の block が実行されます。

    • そうでなければ、次の case_block に対して再び上記の処理が実行されます。

    • これ以上 case block が存在しない場合は、 match 文が終了します。

注釈

基本的に、 match 文のパターンが評価されるという前提でコードを書くべきではありません。 インタープリタの実装によっては、結果をキャッシュするなどの最適化を行い、評価をスキップする可能性があります。

簡単な match 文の例:

>>> flag = False
>>> match (100, 200):
...    case (100, 300):  # Mismatch: 200 != 300
...        print('Case 1')
...    case (100, 200) if flag:  # Successful match, but guard fails
...        print('Case 2')
...    case (100, y):  # Matches and binds y to 200
...        print(f'Case 3, y: {y}')
...    case _:  # Pattern not attempted
...        print('Case 4, I match anything!')
...
Case 3, y: 200

この例では、 if flag がガードです。 ガードについては次のセクションを参照してください。

8.6.2. ガード

guard ::=  "if" named_expression

guard (case 一部として現れる) が成功してはじめて、その case ブロックのコードが実行されます。 ガードは if の後に式を書く形で表記されます。

guard 付きの case ブロックの処理の流れは次のとおりです:

  1. case ブロックのパターンが成功するかどうかをチェックする。 失敗した場合は、 guard は評価されず、次の case ブロックのチェックに進む。

  2. パターンが成功した場合は、 guard の評価が行われます。

    • guard 条件の評価値が真である場合、該当の case ブロックが選択されます。

    • guard 条件の評価値が偽の場合、該当の case ブロックは選択されません。

    • guard の評価中に例外が送出された場合は、その例外がそのまま送出されます。

ガードは式であるため、副作用を起こすことができます。 ガードの評価は、最初の case ブロックから順に、パターンが失敗した case ブロックは飛ばしつつ、一つづつ評価されなければいけません (つまり、ガードの評価は書かれている順番で実行される必要があります)。 また、case ブロックが選択された時点で、ガードの評価をそれ以上行ってはいけません。

8.6.3. 論駁不可能なケースブロック

論駁不可能なケースブロックとは、何にでもマッチするケースブロックのことです。 match 文の中で、論駁不可能なケースブロックは最大一つまで、かつ最後に位置する必要があります。

ケースブロックが論駁不可能であるためには、ガードがなく、パターンが論駁不可能である必要があります。 パターンが論駁不可能であるためには、その文法上の構造のみから、それが常に成功することが証明できる必要があります。 論駁不可能なパターンは以下のようなもののみです:

8.6.4. パターン

注釈

このセクションでは、通常のEBNFを拡張した文法記法を使用します。

  • SEP.RULE+ という表記は RULE (SEP RULE)* の略です。

  • !RULE は否定先読みの条件を表します。

patterns のトップレベルの構文は以下の通りです:

patterns       ::=  open_sequence_pattern | pattern
pattern        ::=  as_pattern | or_pattern
closed_pattern ::=  | literal_pattern
                    | capture_pattern
                    | wildcard_pattern
                    | value_pattern
                    | group_pattern
                    | sequence_pattern
                    | mapping_pattern
                    | class_pattern

以下の説明では分かりやすさのため、パターンの振る舞いを簡単に言い表した場合の説明を「簡単に言うと」の後に書いています (そのほとんどは、Raymond Hettinger 氏のドキュメントに影響を受けてのものです)。 ただし、これはあくまで理解を助けるためのであり、内部的な実装を必ずしも反映したものでは ありません 。 また、使用可能なすべてのパターン構造を網羅しているわけではありません。

8.6.4.1. OR パターン

OR パターンは、縦線 | で区切られた複数のパターンからなります。 構文:

or_pattern ::=  "|".closed_pattern+

最後のサブパターン以外、 論駁不可能 であってはいけません。 また、曖昧さ回避のため、各サブパターンが束縛する名前の組み合わせは、すべて同じである必要があります。

OR パターンでは、サブジェクト値に対して順に各サブパターンのマッチングが行われます。 マッチが成功するとそこで終了し、この OR パターンは成功したとみなされます。 一方、どのサブパターンも成功しなければ、この OR パターンは失敗したことになります。

簡単に言うと、 P1 | P2 | ... というパターンは P1 をマッチしようとし、失敗すれば P2 を試します。 いずれかのパターンがマッチが成功すれば直ちに成功となり、それ以外の場合は失敗となります。

8.6.4.2. AS パターン

AS パターンはサブジェクト値に対して、 as キーワードの左側にある OR パターンをマッチさせます。 構文:

as_pattern ::=  or_pattern "as" capture_pattern

OR パターンが失敗すれば、この AS パターンは失敗となります。 成功すれば、サブジェクト値が as キーワードの右側の名前に束縛され、この AS パターンは成功となります。 capture_pattern として _ を指定することはできません。

簡単に言うと、 P as NAMEP をマッチさせ、成功した場合に NAME = <subject> の代入を行います。

8.6.4.3. リテラルパターン

リテラルパターンは、一部を除く Python の リテラル に対応します。 構文:

literal_pattern ::=  signed_number
                     | signed_number "+" NUMBER
                     | signed_number "-" NUMBER
                     | strings
                     | "None"
                     | "True"
                     | "False"
                     | signed_number: NUMBER | "-" NUMBER

strings というルールと NUMBER というトークンは Python の文法仕様 で定義されています。 クォート3つで囲われた文字列や raw 文字列、 raw バイト列も使用可能です。 f-strings は使用できません。

signed_number '+' NUMBERsigned_number '-' NUMBER という構文は 複素数 を表現するためのものです。 そのため、左側には実数、右側には虚数を書く必要があります。 例: 3 + 4j

簡単に言うと、 LITERAL<subject> == LITERAL であるときのみ成功するパターンです。 シングルトンである NoneTrueFalseis 演算子を使って比較されます。

8.6.4.4. キャプチャパターン

キャプチャパターンは、サブジェクト値を名前に束縛します。 構文:

capture_pattern ::=  !'_' NAME

アンダースコア一文字の _ はキャプチャパターンではありません (!'_' が表しているのはこの条件です) 。 wildcard_pattern として扱われます。

パターン一つの中で、一つの名前は一度しか束縛することができません。 例えば、 case x, x: ... は間違いですが、 case [x] | x: ... は正しいです。

キャプチャパターンは常に成功します。 束縛された名前のスコープは、 PEP 572 で確立された代入式演算子のスコープルールと同じです。 すなわち、当てはまる global 文 か nonlocal 文がない限り、その局所変数のスコープは、該当の match 文を包む最も内側の関数となります。

簡単に言うと、 NAME は常に成功し、 NAME = <subject> の代入が行われます。

8.6.4.5. ワイルドカードパターン

ワイルドカードパターンは常に成功 (何に対してもマッチする) し、名前の束縛はしません。 構文:

wildcard_pattern ::=  '_'

_ は、パターンの中で使用された場合は常に ソフトキーワード です。 しかし、パターンの中でない場合はソフトキーワードではありません。 たとえサブジェクト式や guardcase ブロックの中でも、通常の変数となります。

簡単に言うと、 _ は常に成功します。

8.6.4.6. 値パターン

値パターンは Python で名前の付けられた値を表します。 構文:

value_pattern ::=  attr
attr          ::=  name_or_attr "." NAME
name_or_attr  ::=  attr | NAME

ドットがついたこの名前は、Python 標準の 名前解決ルール によって解決されます。 このパターンは、解決された値がサブジェクト値と等しい (比較演算子 == に基づく) ときに成功となります。

簡単に言うと、 NAME1.NAME2<subject> == NAME1.NAME2 であるときのみ成功します。

注釈

一つの match 文で同じ値が複数回出現する場合は、インタープリタが最初に解決された値をキャッシュし、名前解決を何度も行うことなく値を再利用する可能性があります。 このキャッシュは、その match 文のその実行一回の間だけで再利用されます。

8.6.4.7. グループパターン

A group pattern allows users to add parentheses around patterns to emphasize the intended grouping. Otherwise, it has no additional syntax. Syntax:

group_pattern ::=  "(" pattern ")"

In simple terms (P) has the same effect as P.

8.6.4.8. シーケンスパターン

A sequence pattern contains several subpatterns to be matched against sequence elements. The syntax is similar to the unpacking of a list or tuple.

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)

There is no difference if parentheses or square brackets are used for sequence patterns (i.e. (...) vs [...] ).

注釈

A single pattern enclosed in parentheses without a trailing comma (e.g. (3 | 4)) is a group pattern. While a single pattern enclosed in square brackets (e.g. [3 | 4]) is still a sequence pattern.

At most one star subpattern may be in a sequence pattern. The star subpattern may occur in any position. If no star subpattern is present, the sequence pattern is a fixed-length sequence pattern; otherwise it is a variable-length sequence pattern.

The following is the logical flow for matching a sequence pattern against a subject value:

  1. If the subject value is not a sequence [2], the sequence pattern fails.

  2. If the subject value is an instance of str, bytes or bytearray the sequence pattern fails.

  3. The subsequent steps depend on whether the sequence pattern is fixed or variable-length.

    If the sequence pattern is fixed-length:

    1. If the length of the subject sequence is not equal to the number of subpatterns, the sequence pattern fails

    2. Subpatterns in the sequence pattern are matched to their corresponding items in the subject sequence from left to right. Matching stops as soon as a subpattern fails. If all subpatterns succeed in matching their corresponding item, the sequence pattern succeeds.

    Otherwise, if the sequence pattern is variable-length:

    1. If the length of the subject sequence is less than the number of non-star subpatterns, the sequence pattern fails.

    2. The leading non-star subpatterns are matched to their corresponding items as for fixed-length sequences.

    3. If the previous step succeeds, the star subpattern matches a list formed of the remaining subject items, excluding the remaining items corresponding to non-star subpatterns following the star subpattern.

    4. Remaining non-star subpatterns are matched to their corresponding subject items, as for a fixed-length sequence.

    注釈

    The length of the subject sequence is obtained via len() (i.e. via the __len__() protocol). This length may be cached by the interpreter in a similar manner as value patterns.

In simple terms [P1, P2, P3, ... , P<N>] matches only if all the following happens:

  • <subject> がシーケンスかをチェックする

  • len(subject) == <N>

  • P1 matches <subject>[0] (note that this match can also bind names)

  • P2 matches <subject>[1] (note that this match can also bind names)

  • ... and so on for the corresponding pattern/element.

8.6.4.9. マッピングパターン

A mapping pattern contains one or more key-value patterns. The syntax is similar to the construction of a dictionary. Syntax:

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

At most one double star pattern may be in a mapping pattern. The double star pattern must be the last subpattern in the mapping pattern.

Duplicate keys in mapping patterns are disallowed. Duplicate literal keys will raise a SyntaxError. Two keys that otherwise have the same value will raise a ValueError at runtime.

The following is the logical flow for matching a mapping pattern against a subject value:

  1. If the subject value is not a mapping [3],the mapping pattern fails.

  2. If every key given in the mapping pattern is present in the subject mapping, and the pattern for each key matches the corresponding item of the subject mapping, the mapping pattern succeeds.

  3. If duplicate keys are detected in the mapping pattern, the pattern is considered invalid. A SyntaxError is raised for duplicate literal values; or a ValueError for named keys of the same value.

注釈

Key-value pairs are matched using the two-argument form of the mapping subject's get() method. Matched key-value pairs must already be present in the mapping, and not created on-the-fly via __missing__() or __getitem__().

In simple terms {KEY1: P1, KEY2: P2, ... } matches only if all the following happens:

  • <subject> がマッピングかをチェックする

  • KEY1 in <subject>

  • P1<subject>[KEY1] にマッチする

  • ... and so on for the corresponding KEY/pattern pair.

8.6.4.10. クラスパターン

A class pattern represents a class and its positional and keyword arguments (if any). Syntax:

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

The same keyword should not be repeated in class patterns.

The following is the logical flow for matching a class pattern against a subject value:

  1. If name_or_attr is not an instance of the builtin type , raise TypeError.

  2. If the subject value is not an instance of name_or_attr (tested via isinstance()), the class pattern fails.

  3. If no pattern arguments are present, the pattern succeeds. Otherwise, the subsequent steps depend on whether keyword or positional argument patterns are present.

    For a number of built-in types (specified below), a single positional subpattern is accepted which will match the entire subject; for these types keyword patterns also work as for other types.

    If only keyword patterns are present, they are processed as follows, one by one:

    I. The keyword is looked up as an attribute on the subject.

    • If this raises an exception other than AttributeError, the exception bubbles up.

    • If this raises AttributeError, the class pattern has failed.

    • Else, the subpattern associated with the keyword pattern is matched against the subject's attribute value. If this fails, the class pattern fails; if this succeeds, the match proceeds to the next keyword.

    II. If all keyword patterns succeed, the class pattern succeeds.

    If any positional patterns are present, they are converted to keyword patterns using the __match_args__ attribute on the class name_or_attr before matching:

    I. The equivalent of getattr(cls, "__match_args__", ()) is called.

    • If this raises an exception, the exception bubbles up.

    • If the returned value is not a tuple, the conversion fails and TypeError is raised.

    • If there are more positional patterns than len(cls.__match_args__), TypeError is raised.

    • Otherwise, positional pattern i is converted to a keyword pattern using __match_args__[i] as the keyword. __match_args__[i] must be a string; if not TypeError is raised.

    • If there are duplicate keywords, TypeError is raised.

    II. Once all positional patterns have been converted to keyword patterns,

    the match proceeds as if there were only keyword patterns.

    For the following built-in types the handling of positional subpatterns is different:

    These classes accept a single positional argument, and the pattern there is matched against the whole object rather than an attribute. For example int(0|1) matches the value 0, but not the value 0.0.

In simple terms CLS(P1, attr=P2) matches only if the following happens:

  • isinstance(<subject>, CLS)

  • convert P1 to a keyword pattern using CLS.__match_args__

  • For each keyword argument attr=P2:

    • hasattr(<subject>, "attr")

    • P2<subject>.attr にマッチする

  • ... and so on for the corresponding keyword argument/pattern pair.

参考

  • PEP 634 -- 構造的パターンマッチ: 仕様

  • PEP 636 -- 構造的パターンマッチ: チュートリアル

8.7. 関数定義

関数定義は、ユーザ定義関数オブジェクトを定義します (標準型の階層 節参照):

funcdef                   ::=  [decorators] "def" funcname [type_params] "(" [parameter_list] ")"
                               ["->" expression] ":" suite
decorators                ::=  decorator+
decorator                 ::=  "@" assignment_expression NEWLINE
parameter_list            ::=  defparameter ("," defparameter)* "," "/" ["," [parameter_list_no_posonly]]
                                 | parameter_list_no_posonly
parameter_list_no_posonly ::=  defparameter ("," defparameter)* ["," [parameter_list_starargs]]
                               | parameter_list_starargs
parameter_list_starargs   ::=  "*" [parameter] ("," defparameter)* ["," ["**" parameter [","]]]
                               | "**" parameter [","]
parameter                 ::=  identifier [":" expression]
defparameter              ::=  parameter ["=" expression]
funcname                  ::=  identifier

関数定義は実行可能な文です。関数定義を実行すると、現在のローカルな名前空間内で関数名を関数オブジェクト (関数の実行可能コードをくるむラッパー) に束縛します。この関数オブジェクトには、関数が呼び出された際に使われるグローバルな名前空間として、現在のグローバルな名前空間への参照が入っています。

関数定義は関数本体を実行しません; 関数本体は関数が呼び出された時にのみ実行されます。 [4]

関数定義は一つ以上の デコレータ 式でラップできます。デコレータ式は関数を定義するとき、関数定義の入っているスコープで評価されます。その結果は、関数オブジェクトを唯一の引数にとる呼び出し可能オブジェクトでなければなりません。関数オブジェクトの代わりに、返された値が関数名に束縛されます。複数のデコレータはネストして適用されます。例えば、以下のようなコード:

@f1(arg)
@f2
def func(): pass

は、だいたい次と等価です

def func(): pass
func = f1(arg)(f2(func))

ただし、前者のコードでは元々の関数を func という名前へ一時的に束縛することはない、というところを除きます。

バージョン 3.9 で変更: Functions may be decorated with any valid assignment_expression. Previously, the grammar was much more restrictive; see PEP 614 for details.

A list of type parameters may be given in square brackets between the function's name and the opening parenthesis for its parameter list. This indicates to static type checkers that the function is generic. At runtime, the type parameters can be retrieved from the function's __type_params__ attribute. See Generic functions for more.

バージョン 3.12 で変更: Type parameter lists are new in Python 3.12.

1 つ以上の 仮引数parameter = expression の形を取っているとき、関数は "デフォルト引数値" を持つと言います。デフォルト値を持つ仮引数では、呼び出し時にそれに対応する 実引数 は省略でき、その場合は仮引数のデフォルト値が使われます。ある引数がデフォルト値を持っている場合、それ以降 "*" が出てくるまでの引数は全てデフォルト値を持っていなければなりません -- これは文法定義では表現されていない構文的制限です。

デフォルト引数値は関数定義が実行されるときに左から右へ評価されます。 これは、デフォルト引数の式は関数が定義されるときにただ一度だけ評価され、同じ "計算済みの" 値が呼び出しのたびに使用されることを意味します。この仕様を理解しておくことは特に、デフォルト引数値がリストや辞書のようなミュータブルなオブジェクトであるときに重要です: 関数がこのオブジェクトを変更 (例えばリストに要素を追加) すると、このデフォルト引数値が変更の影響を受けてしまします。一般には、これは意図しない動作です。このような動作を避けるには、デフォルト値として None を使い、この値を関数本体の中で明示的にテストします。例えば以下のようにします:

def whats_on_the_telly(penguin=None):
    if penguin is None:
        penguin = []
    penguin.append("property of the zoo")
    return penguin

関数呼び出しの意味付けに関する詳細は、 呼び出し (call) 節で述べられています。 関数呼び出しを行うと、パラメタリストに記述された全てのパラメタに、位置引数、キーワード引数、デフォルト値のいずれかから値が代入されます。 "*identifier" 形式が存在すれば、余ったすべての位置引数を受け取ったタプルに初期化されます。 このデフォルト値は空のタプルです。 "**identifier" 形式が存在すれば、余ったすべてのキーワード引数を受け取った順序付きのマッピングオブジェクトに初期化されます。 このデフォルト値は同じ型の空のマッピングオブジェクトです。 "*" や "*identifier" の後のパラメタはキーワード専用パラメータで、キーワード引数によってのみ渡されます。 "/" の前のパラメタは位置専用パラメータで、位置引数によってのみ渡されます。

バージョン 3.8 で変更: The / function parameter syntax may be used to indicate positional-only parameters. See PEP 570 for details.

引数には、引数名に続けて ": expression" 形式の アノテーション を付けられます。 *identifier**identifier の形式でも、すべての引数にはアノテーションをつけられます。 関数には、引数リストの後に "-> expression" 形式の "return" アノテーションをつけられます。これらのアノテーションは、任意の有効な Python の式が使えます。 アノテーションがあっても、関数の意味論は変わりません。 アノテーションの値は、関数オブジェクトの __annotations__ 属性の、引数名をキーとする値として得られます。 __future__annotations インポートを使った場合は、アノテーションは実行時には文字列として保持され、これにより評価の遅延が可能になっています。 そうでない場合は、アノテーションは関数定義が実行されたときに評価されます。 このケースでは、アノテーションはソースコードに現れたのとは違う順序で評価されることがあります。

式を即時に使用するために、無名関数 (名前に束縛されていない関数) を作成することもできます。 これは ラムダ (lambda) の節で解説されているラムダ式を使います。 ラムダ式は簡略化された関数定義の簡略表現に過ぎないことに注意してください; "def" 文で定義された関数もラムダ式で作成された関数のように、引数として渡せたり、他の名前に割り当てることができます。 複数の式とアノテーションが実行できるので、 "def" 形式の方がより強力です。

プログラマへのメモ: 関数は第一級オブジェクトです。関数定義内で実行された "def" 文は、返り値や引数として渡せるローカル関数を定義します。ネストした関数内で使われる自由変数は、 def を含んでいる関数のローカル変数にアクセスできます。詳細は 名前づけと束縛 (naming and binding) 節を参照してください。

参考

PEP 3107 - Function Annotations

関数アノテーションの元の仕様書。

PEP 484 - 型ヒント

アノテーションの標準的な意味付けである型ヒントの定義。

PEP 526 - Syntax for Variable Annotations

Ability to type hint variable declarations, including class variables and instance variables.

PEP 563 - アノテーションの遅延評価

実行時にアノテーションを貪欲評価するのではなく文字列形式で保持することによる、アノテーションにおける前方参照のサポート

PEP 318 - Decorators for Functions and Methods

Function and method decorators were introduced. Class decorators were introduced in PEP 3129.

8.8. クラス定義

クラス定義は、クラスオブジェクトを定義します (標準型の階層 節参照):

classdef    ::=  [decorators] "class" classname [type_params] [inheritance] ":" suite
inheritance ::=  "(" [argument_list] ")"
classname   ::=  identifier

クラス定義は実行可能な文です。継承リストは通常、基底クラスリストを与えます (より高度な使い方は、 メタクラス を参照してください)。ですから、リストのそれぞれの要素の評価はサブクラス化しても良いクラスであるべきです。継承リストのないクラスは、デフォルトで、基底クラス object を継承するので:

class Foo:
    pass

は、以下と同等です

class Foo(object):
    pass

次にクラスのスイートが、新たな実行フレーム (名前づけと束縛 (naming and binding) を参照してください) 内で、新たに作られたローカル名前空間と元々のグローバル名前空間を使って実行されます (通常、このスイートには主に関数定義が含まれます)。クラスのスイートが実行し終えると、実行フレームは破棄されますが、ローカルな名前空間は保存されます。[5] 次に、継承リストを基底クラスに、保存されたローカル名前空間を属性値辞書に、それぞれ使ってクラスオブジェクトが生成されます。最後に、もとのローカル名前空間において、クラス名がこのクラスオブジェクトに束縛されます。

クラス本体で属性が定義された順序は新しいクラスの __dict__ に保持されます。 この性質が期待できるのは、クラスが作られた直後かつ定義構文を使って定義されたクラスであるときのみです。

クラス作成は、 メタクラス を利用して大幅にカスタマイズできます。

関数をデコレートするのと同じように、クラスもデコレートすることが出来ます、

@f1(arg)
@f2
class Foo: pass

は、だいたい次と等価です

class Foo: pass
Foo = f1(arg)(f2(Foo))

デコレータ式の評価規則は関数デコレータと同じです。結果はクラス名に束縛されます。

バージョン 3.9 で変更: Classes may be decorated with any valid assignment_expression. Previously, the grammar was much more restrictive; see PEP 614 for details.

A list of type parameters may be given in square brackets immediately after the class's name. This indicates to static type checkers that the class is generic. At runtime, the type parameters can be retrieved from the class's __type_params__ attribute. See Generic classes for more.

バージョン 3.12 で変更: Type parameter lists are new in Python 3.12.

プログラマのための注釈: クラス定義内で定義された変数はクラス属性であり、全てのインスタンス間で共有されます。インスタンス属性は、メソッドの中で self.name = value とすることで設定できます。クラス属性もインスタンス属性も "self.name" 表記でアクセスでき、この表記でアクセスしたとき、インスタンス属性は同名のクラス属性を隠蔽します。クラス属性は、インスタンス属性のデフォルト値として使えますが、そこにミュータブルな値を使うと予期せぬ結果につながります。 記述子 を使うと、詳細な実装が異なるインスタンス変数を作成できます。

参考

PEP 3115 - Metaclasses in Python 3000

メタクラスの宣言を現在の文法と、メタクラス付きのクラスがどのように構築されるかの意味論を変更した提案

PEP 3129 - クラスデコレータ

クラスデコレータを追加した提案。 関数デコレータとメソッドデコレータは PEP 318 で導入されました。

8.9. コルーチン

Added in version 3.5.

8.9.1. コルーチン関数定義

async_funcdef ::=  [decorators] "async" "def" funcname "(" [parameter_list] ")"
                   ["->" expression] ":" suite

Python で実行しているコルーチンは多くの時点で一時停止と再開ができます (coroutine を参照)。await 式である async forasync with はコルーチン関数の本体でしか使えません。

Functions defined with async def syntax are always coroutine functions, even if they do not contain await or async keywords.

コルーチン関数の本体の中で yield from 式を使用すると SyntaxError になります。

コルーチン関数の例:

async def func(param1, param2):
    do_stuff()
    await some_coroutine()

バージョン 3.7 で変更: await and async are now keywords; previously they were only treated as such inside the body of a coroutine function.

8.9.2. async for

async_for_stmt ::=  "async" for_stmt

asynchronous iterable は、その __anext__ メソッドで非同期なコードを実行可能な、asynchronous iterator を直接返す __aiter__ メソッドを提供しています。

async for 文によって非同期なイテラブルを簡単にイテレーションすることができます。

以下のコード:

async for TARGET in ITER:
    SUITE
else:
    SUITE2

は意味論的に以下と等価です:

iter = (ITER)
iter = type(iter).__aiter__(iter)
running = True

while running:
    try:
        TARGET = await type(iter).__anext__(iter)
    except StopAsyncIteration:
        running = False
    else:
        SUITE
else:
    SUITE2

詳細は __aiter__()__anext__() を参照してください。

コルーチン関数の本体の外で async for 文を使用すると SyntaxError になります。

8.9.3. async with

async_with_stmt ::=  "async" with_stmt

asynchronous context manager は、 enter メソッドと exit メソッド内部で実行を一時停止できる context manager です。

以下のコード:

async with EXPRESSION as TARGET:
    SUITE

これは次と等価です:

manager = (EXPRESSION)
aenter = type(manager).__aenter__
aexit = type(manager).__aexit__
value = await aenter(manager)
hit_except = False

try:
    TARGET = value
    SUITE
except:
    hit_except = True
    if not await aexit(manager, *sys.exc_info()):
        raise
finally:
    if not hit_except:
        await aexit(manager, None, None, None)

詳細は __aenter__()__aexit__() を参照してください。

コルーチン関数の本体の外で async with 文を使用すると SyntaxError になります。

参考

PEP 492 - async 構文および await 構文付きのコルーチン

コルーチンを Python のまともな独り立ちした概念にし、サポートする構文を追加した提案。

8.10. Type parameter lists

Added in version 3.12.

バージョン 3.13 で変更: Support for default values was added (see PEP 696).

type_params  ::=  "[" type_param ("," type_param)* "]"
type_param   ::=  typevar | typevartuple | paramspec
typevar      ::=  identifier (":" expression)? ("=" expression)?
typevartuple ::=  "*" identifier ("=" expression)?
paramspec    ::=  "**" identifier ("=" expression)?

Functions (including coroutines), classes and type aliases may contain a type parameter list:

def max[T](args: list[T]) -> T:
    ...

async def amax[T](args: list[T]) -> T:
    ...

class Bag[T]:
    def __iter__(self) -> Iterator[T]:
        ...

    def add(self, arg: T) -> None:
        ...

type ListOrSet[T] = list[T] | set[T]

Semantically, this indicates that the function, class, or type alias is generic over a type variable. This information is primarily used by static type checkers, and at runtime, generic objects behave much like their non-generic counterparts.

Type parameters are declared in square brackets ([]) immediately after the name of the function, class, or type alias. The type parameters are accessible within the scope of the generic object, but not elsewhere. Thus, after a declaration def func[T](): pass, the name T is not available in the module scope. Below, the semantics of generic objects are described with more precision. The scope of type parameters is modeled with a special function (technically, an annotation scope) that wraps the creation of the generic object.

Generic functions, classes, and type aliases have a __type_params__ attribute listing their type parameters.

Type parameters come in three kinds:

  • typing.TypeVar, introduced by a plain name (e.g., T). Semantically, this represents a single type to a type checker.

  • typing.TypeVarTuple, introduced by a name prefixed with a single asterisk (e.g., *Ts). Semantically, this stands for a tuple of any number of types.

  • typing.ParamSpec, introduced by a name prefixed with two asterisks (e.g., **P). Semantically, this stands for the parameters of a callable.

typing.TypeVar declarations can define bounds and constraints with a colon (:) followed by an expression. A single expression after the colon indicates a bound (e.g. T: int). Semantically, this means that the typing.TypeVar can only represent types that are a subtype of this bound. A parenthesized tuple of expressions after the colon indicates a set of constraints (e.g. T: (str, bytes)). Each member of the tuple should be a type (again, this is not enforced at runtime). Constrained type variables can only take on one of the types in the list of constraints.

For typing.TypeVars declared using the type parameter list syntax, the bound and constraints are not evaluated when the generic object is created, but only when the value is explicitly accessed through the attributes __bound__ and __constraints__. To accomplish this, the bounds or constraints are evaluated in a separate annotation scope.

typing.TypeVarTuples and typing.ParamSpecs cannot have bounds or constraints.

All three flavors of type parameters can also have a default value, which is used when the type parameter is not explicitly provided. This is added by appending a single equals sign (=) followed by an expression. Like the bounds and constraints of type variables, the default value is not evaluated when the object is created, but only when the type parameter's __default__ attribute is accessed. To this end, the default value is evaluated in a separate annotation scope. If no default value is specified for a type parameter, the __default__ attribute is set to the special sentinel object typing.NoDefault.

The following example indicates the full set of allowed type parameter declarations:

def overly_generic[
   SimpleTypeVar,
   TypeVarWithDefault = int,
   TypeVarWithBound: int,
   TypeVarWithConstraints: (str, bytes),
   *SimpleTypeVarTuple = (int, float),
   **SimpleParamSpec = (str, bytearray),
](
   a: SimpleTypeVar,
   b: TypeVarWithDefault,
   c: TypeVarWithBound,
   d: Callable[SimpleParamSpec, TypeVarWithConstraints],
   *e: SimpleTypeVarTuple,
): ...

8.10.1. Generic functions

Generic functions are declared as follows:

def func[T](arg: T): ...

This syntax is equivalent to:

annotation-def TYPE_PARAMS_OF_func():
    T = typing.TypeVar("T")
    def func(arg: T): ...
    func.__type_params__ = (T,)
    return func
func = TYPE_PARAMS_OF_func()

Here annotation-def indicates an annotation scope, which is not actually bound to any name at runtime. (One other liberty is taken in the translation: the syntax does not go through attribute access on the typing module, but creates an instance of typing.TypeVar directly.)

The annotations of generic functions are evaluated within the annotation scope used for declaring the type parameters, but the function's defaults and decorators are not.

The following example illustrates the scoping rules for these cases, as well as for additional flavors of type parameters:

@decorator
def func[T: int, *Ts, **P](*args: *Ts, arg: Callable[P, T] = some_default):
    ...

Except for the lazy evaluation of the TypeVar bound, this is equivalent to:

DEFAULT_OF_arg = some_default

annotation-def TYPE_PARAMS_OF_func():

    annotation-def BOUND_OF_T():
        return int
    # In reality, BOUND_OF_T() is evaluated only on demand.
    T = typing.TypeVar("T", bound=BOUND_OF_T())

    Ts = typing.TypeVarTuple("Ts")
    P = typing.ParamSpec("P")

    def func(*args: *Ts, arg: Callable[P, T] = DEFAULT_OF_arg):
        ...

    func.__type_params__ = (T, Ts, P)
    return func
func = decorator(TYPE_PARAMS_OF_func())

The capitalized names like DEFAULT_OF_arg are not actually bound at runtime.

8.10.2. Generic classes

Generic classes are declared as follows:

class Bag[T]: ...

This syntax is equivalent to:

annotation-def TYPE_PARAMS_OF_Bag():
    T = typing.TypeVar("T")
    class Bag(typing.Generic[T]):
        __type_params__ = (T,)
        ...
    return Bag
Bag = TYPE_PARAMS_OF_Bag()

Here again annotation-def (not a real keyword) indicates an annotation scope, and the name TYPE_PARAMS_OF_Bag is not actually bound at runtime.

Generic classes implicitly inherit from typing.Generic. The base classes and keyword arguments of generic classes are evaluated within the type scope for the type parameters, and decorators are evaluated outside that scope. This is illustrated by this example:

@decorator
class Bag(Base[T], arg=T): ...

これは次と等価です:

annotation-def TYPE_PARAMS_OF_Bag():
    T = typing.TypeVar("T")
    class Bag(Base[T], typing.Generic[T], arg=T):
        __type_params__ = (T,)
        ...
    return Bag
Bag = decorator(TYPE_PARAMS_OF_Bag())

8.10.3. Generic type aliases

The type statement can also be used to create a generic type alias:

type ListOrSet[T] = list[T] | set[T]

Except for the lazy evaluation of the value, this is equivalent to:

annotation-def TYPE_PARAMS_OF_ListOrSet():
    T = typing.TypeVar("T")

    annotation-def VALUE_OF_ListOrSet():
        return list[T] | set[T]
    # In reality, the value is lazily evaluated
    return typing.TypeAliasType("ListOrSet", VALUE_OF_ListOrSet(), type_params=(T,))
ListOrSet = TYPE_PARAMS_OF_ListOrSet()

Here, annotation-def (not a real keyword) indicates an annotation scope. The capitalized names like TYPE_PARAMS_OF_ListOrSet are not actually bound at runtime.

脚注