8. 複合文 (compound statement)¶
複合文には、他の文 (のグループ) が入ります; 複合文は、中に入っている他の文の実行の制御に何らかのやり方で影響を及ぼします。一般的には、複合文は複数行にまたがって書かれますが、全部の文を一行に連ねた単純な書き方もあります。
if 、 while 、および 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_funcdefsuite:stmt_listNEWLINE | NEWLINE INDENTstatement+ DEDENT statement:stmt_listNEWLINE |compound_stmtstmt_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_expression_list":"suite["else" ":"suite]
starred_expression_list の式を一度評価します。
結果は イテラブル オブジェクトでなければなりません。
そのイテラブルに対する イテレータ を作成します。
次に、イテレータが返す最初の要素を、通常の代入規則 (代入文 (assignment statement) を参照) に従ってターゲットリストに代入し、スイートを実行します。
これをイテレータが返す要素ごとに繰り返します。
イテレータを 使い果たす と、else 節があればそのスイートを実行し、ループを終了します。
最初のスイートの中で break 文が実行されると、 else 節のスイートを実行することなくループを終了します。
continue 文が最初のスイート内で実行されると、スイート内にある残りの文の実行をスキップして、次の要素の処理に移るか、これ以上次の要素が無い場合は else 節の処理に移ります。
for ループはターゲットリスト内の変数への代入を行います。 これにより、for ループ内も含めて、それ以前の全ての代入は上書きされます:
for i in range(10):
print(i)
i = 5 # for ループには影響しない。
# i は range の次のインデックスで
# 上書きされるため。
ループが終了してもターゲットリスト内の名前は削除されませんが、イテラブルが空の場合には、ループでの代入は全く行われません。ヒント: 組み込み型 range() は、 整数の不変算術列を表します。例えば、 range(3) を反復すると0、1そして2の順に結果を返します。
バージョン 3.11 で変更: 式のリストの中でアスタリスク付きの式 (starred elements) を指定できるようになりました。
8.4. try 文¶
try 文は、ひとまとめの文に対して、例外処理および/またはクリーンアップコードを指定します:
try_stmt:try1_stmt|try2_stmt|try3_stmttry1_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 文 節にあります。
バージョン 3.14 で変更: 複数の例外型を指定するときに、それらをまとめる丸括弧を省略できるようになりました。 PEP 758 を参照してください。
8.4.1. except 節¶
except 節は、一つ以上の例外ハンドラーを指定します。
try 節で例外が起きなければ、例外ハンドラーは実行されません。
try スイートで例外が起きると、例外ハンドラーの検索が始まります。
この検索では、例外に一致するものが見付かるまで except 節を順に調べます。
式を持たない except 節を指定する場合、それは最後になければなりません。
この節は、すべての例外に一致します。
式を持つ except 節では、その式は例外型か例外型のタプルに評価されなければなりません。
複数の例外型を指定し、as 節を使わない場合は、丸括弧を省略できます。
送出された例外は、式の評価結果が例外オブジェクトのクラスか、その 仮想でない基底クラス、またはそのようなクラスを含むタプルになる except 節に一致します。
例外がどの 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* 節¶
except* 節は、例外グループ (BaseExceptionGroup のインスタンス) を処理するハンドラーを一つ以上指定します。
try 文には except 節か except* 節のどちらかを指定でき、両方は指定できません。
except* では照合する例外型が必須なので、except*: は構文エラーです。
型は except と同じように解釈しますが、照合は処理中のグループに含まれる例外に対して行います。
照合する型が BaseExceptionGroup のサブクラスの場合、意味が曖昧になるため TypeError を送出します。
try ブロックで例外グループが送出されると、各 except* 節はそれを一致する例外と一致しない例外のサブグループに分割します (split() を参照)。
一致するサブグループが空でなければ、それが処理中の例外 (sys.exception() が返す値) となり、except* 節にターゲットがあれば代入されます。
その後、except* 節の本体を実行します。
一致しないサブグループが空でなければ、次の except* が同じように処理します。
グループ内のすべての例外が一致するか、最後の except* 節を実行するまで、これを続けます。
すべての except* 節を実行した後、未処理の例外のグループを、except* 節の内部で送出または再送出された例外とまとめます。
まとめられた例外グループは、その先へ伝播します。
>>> 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 "<doctest default[0]>", line 2, in <module>
| raise ExceptionGroup("eg",
| [ValueError(1), TypeError(2), OSError(3), OSError(4)])
| ExceptionGroup: eg (1 sub-exception)
+-+---------------- 1 ----------------
| ValueError: 1
+------------------------------------
try ブロックから送出された例外が例外グループでなく、その型がいずれかの except* 節に一致する場合、その例外を捕捉し、メッセージが空文字列の例外グループで包みます。
これにより、ターゲット e の型は常に BaseExceptionGroup になります。
>>> try:
... raise BlockingIOError
... except* BlockingIOError as e:
... print(repr(e))
...
ExceptionGroup('', (BlockingIOError(),))
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 文を実行した場合、保存された例外は破棄します。
例えば、次の関数は 42 を返します。
def f():
try:
1/0
finally:
return 42
finally 節を実行している間は、プログラムからは例外情報は利用できません。
try...finally 文の try スイート内で return 、 break 、または continue 文が実行された場合、 finally 節も、この文を '抜け出る途中に' 実行されます。
関数の戻り値は、最後に実行した return 文で決まります。
finally 節は常に実行されるため、finally 節の中で実行する return 文は常に最後に実行されるものになります。
次の関数は 'finally' を返します。
def foo():
try:
return 'try'
finally:
return 'finally'
バージョン 3.8 で変更: Python 3.8 より前は、実装上の問題により finally 節で continue 文を使うことはできませんでした。
バージョン 3.14 で変更: finally ブロックに return、break、continue がある場合、コンパイラは SyntaxWarning を発するようになりました (PEP 765 を参照)。
8.5. with 文¶
with 文は、ブロックの実行を、コンテキストマネージャによって定義されたメソッドでラップするために使われます (with文とコンテキストマネージャ セクションを参照してください)。これにより、よくある try...except...finally 利用パターンをカプセル化して便利に再利用することができます。
with_stmt: "with" ( "("with_stmt_contents","? ")" |with_stmt_contents) ":"suitewith_stmt_contents:with_item(","with_item)* with_item:expression["as"target]
一つの "要素" を持つ with 文の実行は以下のように進行します:
コンテキスト式 (
with_itemで与えられた式) を評価することで、コンテキストマネージャを取得します。コンテキストマネージャの
__enter__()メソッドが、後で使うためにロードされます。コンテキストマネージャの
__exit__()メソッドが、後で使うためにロードされます。コンテキストマネージャの
__enter__()メソッドが呼ばれます。with文にターゲットが含まれていたら、それに__enter__()からの戻り値が代入されます。注釈
with文は、__enter__()メソッドがエラーなく終了した場合には__exit__()が常に呼ばれることを保証します。ですので、もしターゲットリストへの代入中にエラーが発生した場合には、これはそのスイートの中で発生したエラーと同じように扱われます。以下のステップ 7 を参照してください。スイートが実行されます。
コンテキストマネージャの
__exit__()メソッドが呼ばれます。スイートが例外によって終了されたのなら、その例外の型、値、トレースバックが__exit__()に引数として渡されます。そうでなければ、 3 つのNone引数が与えられます。スイートが例外により終了され、
__exit__()メソッドからの戻り値が偽(false)ならば、例外が再送出されます。この戻り値が真(true)ならば例外は抑制され、実行はwith文の次の文から続きます。もしそのスイートが例外でない何らかの理由で終了した場合、その
__exit__()からの戻り値は無視されて、実行は発生した終了の種類に応じた通常の位置から継続します。
以下のコード:
with EXPRESSION as TARGET:
SUITE
これは次と等価です:
manager = (EXPRESSION)
enter = manager.__enter__
exit = manager.__exit__
value = enter()
hit_except = False
try:
TARGET = value
SUITE
except:
hit_except = True
if not exit(*sys.exc_info()):
raise
finally:
if not hit_except:
exit(None, None, None)
ただし、__enter__() と __exit__() には、暗黙の 特殊メソッドの検索 を使います。
複数の要素があるとき、コンテキストマネージャは複数の 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 で変更: 括弧で囲むことで、文を複数行に分割して書けるようになりました。
8.6. match 文¶
Added in version 3.10.
match 文はパターンマッチングを行う目的で使われます。 構文:
match_stmt: 'match'subject_expr":" NEWLINE INDENTcase_block+ DEDENT subject_expr:flexible_expression"," [flexible_expression_list[',']] |assignment_expressioncase_block: 'case'patterns[guard] ":"suite
注釈
このセクションでは、一重引用符で囲まれているものは ソフトキーワード を表します。
パターンマッチングは、パターン (case の後ろ) とマッチング対象の値 (match の後ろ)を入力とします。
パターン (サブパターンを含みうる) は、マッチング対象の値に対して、マッチするかどうかの判定が行われます。結果として次のことが起こります:
マッチ成功、もしくはマッチ失敗 (パターン成功・失敗とも呼ばれます)。
マッチした値の名前への束縛。必要な条件は後述します。
match と case キーワードは ソフトキーワード です。
8.6.1. 概要¶
match 文の論理的な動作の流れの概要は次の通りです:
サブジェクト式
subject_exprが評価され、サブジェクト値が得られます。 サブジェクト式がコンマを含む場合、 通常のルール に従ってタプルが作成されます。case_block内の各パターンに対して、サブジェクト値がマッチするかどうかをチェックします。 マッチ成功・失敗の具体的なルールは後述します。 マッチングのチェックにより、パターン内の名前の一部あるいはすべてに値が束縛されます。 具体的な束縛ルールはパターンの種類によって異なるため、後述します。 マッチが成功したパターンの中で束縛された名前は、そのパターンのブロック内だけでなく、 match 文の後でも使用することができます。注釈
パターンマッチが全体として失敗しても、その中に含まれるサブパターンが成功する可能性があります。 失敗したマッチで発生する名前束縛を前提としたコードを書かないように気をつけてください。 逆に、マッチが失敗したあとで変数の値が変わっていないというのも前提にしないでください。 実際どういう振る舞いになるかは Python の実装依存であり、実装間で異なる可能性があります。 色々な実装が最適化を行えるよう、意図的に実装依存としています。
パターンが成功した場合、該当のガードが (もしあれば) 評価されます。 この場合、パターン内の名前がすべて束縛されていることが保証されています。
ガードの評価値が真であるか、もしくはガードがなければ、
case_block内のblockが実行されます。そうでなければ、次の
case_blockに対して再び上記の処理が実行されます。これ以上 case block が存在しない場合は、 match 文が終了します。
注釈
基本的に、 match 文のパターンが評価されるという前提でコードを書くべきではありません。 インタープリタの実装によっては、結果をキャッシュするなどの最適化を行い、評価をスキップする可能性があります。
簡単な match 文の例:
>>> flag = False
>>> match (100, 200):
... case (100, 300): # 不一致: 200 != 300
... print('Case 1')
... case (100, 200) if flag: # マッチするが、ガードは失敗する
... print('Case 2')
... case (100, y): # マッチし、y を 200 に束縛する
... print(f'Case 3, y: {y}')
... case _: # このパターンは試さない
... print('Case 4, I match anything!')
...
Case 3, y: 200
この例では、 if flag がガードです。
ガードについては次のセクションを参照してください。
8.6.2. ガード¶
guard: "if" assignment_expression
guard (case 一部として現れる) が成功してはじめて、その case ブロックのコードが実行されます。
ガードは if の後に式を書く形で表記されます。
guard 付きの case ブロックの処理の流れは次のとおりです:
caseブロックのパターンが成功するかどうかをチェックする。 失敗した場合は、guardは評価されず、次のcaseブロックのチェックに進む。パターンが成功した場合は、
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|patternpattern:as_pattern|or_patternclosed_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 NAME は P をマッチさせ、成功した場合に NAME = <subject> の代入を行います。
8.6.4.3. リテラルパターン¶
リテラルパターンは、一部を除く Python の リテラル に対応します。 構文:
literal_pattern:signed_number|signed_number"+" NUMBER |signed_number"-" NUMBER |strings| "None" | "True" | "False" signed_number: ["+" | "-"] NUMBER
規則 strings とトークン NUMBER は 標準の Python 文法 で定義されています。
三重引用符で囲んだ文字列、raw 文字列、バイト文字列を使えます。
f-strings と t-strings は使えません。
signed_number '+' NUMBER と signed_number '-' NUMBER という構文は 複素数 を表現するためのものです。
そのため、左側には実数、右側には虚数を書く必要があります。
例: 3 + 4j 。
簡単に言うと、 LITERAL は <subject> == LITERAL であるときのみ成功するパターンです。
シングルトンである None と True 、 False は is 演算子を使って比較されます。
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: '_'
_ は、パターンの中で使用された場合は常に ソフトキーワード です。
しかし、パターンの中でない場合はソフトキーワードではありません。
たとえサブジェクト式や guard 、 case ブロックの中でも、通常の変数となります。
簡単に言うと、 _ は常に成功します。
8.6.4.6. 値パターン¶
値パターンは Python で名前の付けられた値を表します。 構文:
value_pattern:attrattr:name_or_attr"." NAME name_or_attr:attr| NAME
ドットがついたこの名前は、Python 標準の 名前解決ルール によって解決されます。
このパターンは、解決された値がサブジェクト値と等しい (比較演算子 == に基づく) ときに成功となります。
簡単に言うと、 NAME1.NAME2 は <subject> == NAME1.NAME2 であるときのみ成功します。
注釈
一つの match 文で同じ値が複数回出現する場合は、インタープリタが最初に解決された値をキャッシュし、名前解決を何度も行うことなく値を再利用する可能性があります。 このキャッシュは、その match 文のその実行一回の間だけで再利用されます。
8.6.4.7. グループパターン¶
グループパターンでは、意図したグループ化を強調するためにパターンを丸括弧で囲めます。 それ以外に追加の構文はありません。 構文:
group_pattern: "(" pattern ")"
簡単に言うと、(P) は P と同じ効果を持ちます。
8.6.4.8. シーケンスパターン¶
シーケンスパターンには、シーケンスの要素と照合する複数のサブパターンが含まれます。 構文はリストやタプルのアンパックと似ています。
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|patternstar_pattern: "*" (capture_pattern|wildcard_pattern)
シーケンスパターンを丸括弧で囲むか角括弧で囲むか ((...) と [...]) による違いはありません。
注釈
単一のパターンを末尾のカンマなしで丸括弧で囲んだもの (例: (3 | 4)) は グループパターン です。
一方、単一のパターンを角括弧で囲んだもの (例: [3 | 4]) はシーケンスパターンです。
シーケンスパターンに含められる星付きサブパターンは最大一つです。 星付きサブパターンはどの位置に置いても構いません。 星付きサブパターンがなければ固定長のシーケンスパターン、あれば可変長のシーケンスパターンになります。
シーケンスパターンをサブジェクト値と照合する論理的な処理の流れは次のとおりです:
サブジェクト値がシーケンス [2] でなければ、シーケンスパターンは失敗します。
サブジェクト値が
str、bytes、bytearrayのインスタンスであれば、シーケンスパターンは失敗します。以降の手順は、シーケンスパターンが固定長か可変長かによって異なります。
シーケンスパターンが固定長の場合:
サブジェクトのシーケンスの長さとサブパターンの数が等しくなければ、シーケンスパターンは失敗します。
シーケンスパターン内のサブパターンを、サブジェクトのシーケンスの対応する要素と左から右へ照合します。 サブパターンが一つでも失敗すると、照合を終了します。 すべてのサブパターンが対応する要素との照合に成功すれば、シーケンスパターンは成功します。
シーケンスパターンが可変長の場合:
サブジェクトのシーケンスの長さが、星の付いていないサブパターンの数より少なければ、シーケンスパターンは失敗します。
先頭にある星の付いていないサブパターンは、固定長シーケンスと同じように対応する要素と照合します。
前の手順が成功した場合、星付きサブパターンは残りのサブジェクトの要素から作ったリストと照合します。 ただし、星付きサブパターンより後にある、星の付いていないサブパターンに対応する要素は、そのリストから除きます。
残りの星の付いていないサブパターンは、固定長シーケンスと同じように対応するサブジェクトの要素と照合します。
簡単に言うと、[P1, P2, P3, ... , P<N>] は、次のすべての条件を満たす場合にだけマッチします:
<subject>がシーケンスかをチェックするlen(subject) == <N>P1が<subject>[0]にマッチする (この照合によって名前が束縛される場合もあります)P2が<subject>[1]にマッチする (この照合によって名前が束縛される場合もあります)... 以降も、対応するパターンと要素について同様です。
8.6.4.9. マッピングパターン¶
マッピングパターンには、キーと値のパターンのペアが一つ以上含まれます。 構文は辞書の構築と似ています。 構文:
mapping_pattern: "{" [items_pattern] "}" items_pattern: ",".key_value_pattern+ ","? key_value_pattern: (literal_pattern|value_pattern) ":"pattern|double_star_patterndouble_star_pattern: "**"capture_pattern
マッピングパターンに含められる二重星付きパターンは最大一つです。 二重星付きパターンは、マッピングパターンの最後のサブパターンでなければなりません。
マッピングパターンではキーの重複は認められません。
リテラルのキーが重複すると SyntaxError を送出します。
それ以外の二つのキーが同じ値を持つ場合は、実行時に ValueError を送出します。
マッピングパターンをサブジェクト値と照合する論理的な処理の流れは次のとおりです:
サブジェクト値がマッピング [3] でなければ、マッピングパターンは失敗します。
マッピングパターンに指定したすべてのキーがサブジェクトのマッピングに存在し、各キーに対するパターンがサブジェクトの対応する要素にマッチすれば、マッピングパターンは成功します。
マッピングパターンにキーの重複が見付かると、そのパターンは無効と見なされます。 リテラルの値が重複している場合は
SyntaxErrorを、名前付きのキーが同じ値を持つ場合はValueErrorを送出します。
注釈
キーと値のペアは、サブジェクトのマッピングの get() メソッドを二つの引数で呼び出して照合します。
照合対象のキーと値のペアは、すでにマッピングに存在していなければなりません。
__missing__() や __getitem__() を通じてその場で作成することはできません。
簡単に言うと、{KEY1: P1, KEY2: P2, ... } は、次のすべての条件を満たす場合にだけマッチします:
<subject>がマッピングかをチェックするKEY1 in <subject>P1は<subject>[KEY1]にマッチする... 以降も、対応する KEY とパターンのペアについて同様です。
8.6.4.10. クラスパターン¶
クラスパターンは、クラスと、位置引数やキーワード引数 (あれば) を表します。 構文:
class_pattern:name_or_attr"(" [pattern_arguments","?] ")" pattern_arguments:positional_patterns[","keyword_patterns] |keyword_patternspositional_patterns: ",".pattern+ keyword_patterns: ",".keyword_pattern+ keyword_pattern: NAME "="pattern
クラスパターン内で同じキーワードを繰り返してはなりません。
クラスパターンをサブジェクト値と照合する論理的な処理の流れは次のとおりです:
サブジェクト値が
name_or_attrのインスタンスでなければ (isinstance()で判定します)、クラスパターンは失敗します。パターン引数がなければ、パターンは成功します。 引数がある場合、以降の手順はキーワード引数パターンがあるか、位置引数パターンがあるかによって異なります。
一部の組み込み型 (後述) は、サブジェクト全体と照合する単一の位置サブパターンを受け付けます。 これらの型でも、キーワードパターンは他の型と同様に動作します。
キーワードパターンだけがある場合は、一つずつ次のように処理します:
キーワードをサブジェクトの属性として検索します。
この処理で
AttributeError以外の例外が起きると、その例外を伝播します。この処理で
AttributeErrorが起きると、クラスパターンは失敗します。それ以外の場合、キーワードパターンに対応するサブパターンを、サブジェクトの属性値と照合します。 失敗すればクラスパターンは失敗し、成功すれば次のキーワードの照合に進みます。
すべてのキーワードパターンが成功すれば、クラスパターンは成功します。
位置パターンがある場合、照合する前に、クラス
name_or_attrの__match_args__属性を使ってキーワードパターンに変換します:getattr(cls, "__match_args__", ())と等価な呼び出しを行います。すべての位置パターンをキーワードパターンに変換した後は、キーワードパターンだけがある場合と同じように照合を進めます。
次の組み込み型では、位置サブパターンの扱いが異なります:
これらのクラスは単一の位置引数を受け付け、そこにあるパターンを属性ではなくオブジェクト全体と照合します。 例えば
int(0|1)は値0にはマッチしますが、値0.0にはマッチしません。
簡単に言うと、CLS(P1, attr=P2) は、次の条件を満たす場合にだけマッチします:
isinstance(<subject>, CLS)CLS.__match_args__を使ってP1をキーワードパターンに変換する各キーワード引数
attr=P2について:hasattr(<subject>, "attr")P2は<subject>.attrにマッチする
... 以降も、対応するキーワード引数とパターンのペアについて同様です。
8.7. 関数定義¶
関数定義は、ユーザ定義関数オブジェクトを定義します (標準型の階層 節参照):
funcdef: [decorators] "def"funcname[type_params] "(" [parameter_list] ")" ["->"expression] ":"suitedecorators:decorator+ decorator: "@"assignment_expressionNEWLINE parameter_list:defparameter(","defparameter)* "," "/" ["," [parameter_list_no_posonly]] |parameter_list_no_posonlyparameter_list_no_posonly:defparameter(","defparameter)* ["," [parameter_list_starargs]] |parameter_list_starargsparameter_list_starargs: "*"star_parameter(","defparameter)* ["," [parameter_star_kwargs]] | "*" (","defparameter)+ ["," [parameter_star_kwargs]] |parameter_star_kwargsparameter_star_kwargs: "**"parameter[","] parameter:identifier[":"expression] star_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 で変更: 有効な任意の assignment_expression で関数をデコレートできるようになりました。
以前の文法には、より厳しい制約がありました。
詳しくは PEP 614 を参照してください。
関数名と仮引数リストの開き丸括弧の間に、角括弧で囲んだ 型パラメータ のリストを指定できます。
これは、関数がジェネリックであることを静的型チェッカーに示します。
実行時には、関数の __type_params__ 属性から型パラメータを取得できます。
詳しくは ジェネリック関数 を参照してください。
バージョン 3.12 で変更: 型パラメータリストは 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 で変更: 関数の仮引数で / 構文を使い、位置専用引数を示せるようになりました。
詳しくは PEP 570 を参照してください。
仮引数には、名前の後に : expression の形式で アノテーション を付けられます。
*identifier や **identifier の形式の仮引数も含め、どの仮引数にもアノテーションを付けられます。
特例として、*identifier 形式の仮引数には : *expression というアノテーションを付けられます。
関数には、仮引数リストの後に -> expression の形式で「戻り値」のアノテーションを付けられます。
これらのアノテーションには、有効な任意の Python 式を使えます。
アノテーションの有無によって、関数の意味は変わりません。
アノテーションについての詳細は アノテーション を参照してください。
バージョン 3.11 で変更: *identifier 形式の仮引数に : *expression というアノテーションを付けられるようになりました。
PEP 646 を参照してください。
式の中ですぐに使うために、無名関数 (名前に束縛されていない関数) を作成することもできます。
これには ラムダ (lambda) 節で説明するラムダ式を使います。
ラムダ式は、簡単な関数定義の省略記法にすぎません。
def 文で定義した関数も、ラムダ式で定義した関数と同じように、引数として渡したり別の名前に代入したりできます。
複数の文やアノテーションを使えるため、def 形式のほうが強力です。
プログラマへのメモ: 関数は第一級オブジェクトです。関数定義内で実行された "def" 文は、返り値や引数として渡せるローカル関数を定義します。ネストした関数内で使われる自由変数は、 def を含んでいる関数のローカル変数にアクセスできます。詳細は 名前づけと束縛 (naming and binding) 節を参照してください。
参考
- PEP 3107 - Function Annotations
関数アノテーションの元の仕様書。
- PEP 484 - 型ヒント
アノテーションの標準的な意味付けである型ヒントの定義。
- PEP 526 - Syntax for Variable Annotations
クラス変数やインスタンス変数を含め、変数宣言に型ヒントを付ける機能。
- PEP 563 - アノテーションの遅延評価
実行時にアノテーションを貪欲評価するのではなく文字列形式で保持することによる、アノテーションにおける前方参照のサポート
- PEP 318 - 関数とメソッドのデコレータ
関数とメソッドのデコレータが導入されました。 クラスのデコレータは PEP 3129 で導入されました。
8.8. クラス定義¶
クラス定義は、クラスオブジェクトを定義します (標準型の階層 節参照):
classdef: [decorators] "class"classname[type_params] [inheritance] ":"suiteinheritance: "(" [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 で変更: 有効な任意の assignment_expression でクラスをデコレートできるようになりました。
以前の文法には、より厳しい制約がありました。
詳しくは PEP 614 を参照してください。
クラス名の直後に、角括弧で囲んだ 型パラメータ のリストを指定できます。
これは、クラスがジェネリックであることを静的型チェッカーに示します。
実行時には、クラスの __type_params__ 属性から型パラメータを取得できます。
詳しくは ジェネリッククラス を参照してください。
バージョン 3.12 で変更: 型パラメータリストは Python 3.12 で追加されました。
プログラマのための注釈: クラス定義内で定義された変数はクラス属性であり、全てのインスタンス間で共有されます。インスタンス属性は、メソッドの中で self.name = value とすることで設定できます。クラス属性もインスタンス属性も "self.name" 表記でアクセスでき、この表記でアクセスしたとき、インスタンス属性は同名のクラス属性を隠蔽します。クラス属性は、インスタンス属性のデフォルト値として使えますが、そこにミュータブルな値を使うと予期せぬ結果につながります。 記述子 を使うと、詳細な実装が異なるインスタンス変数を作成できます。
参考
8.8.1. 多重継承¶
Python のクラスは複数の基底クラスを持つことができ、この手法を 多重継承 と呼びます。 基底クラスは、クラス定義でクラス名の後の丸括弧内に、カンマで区切って列挙します。 例えば、次のクラス定義は、
>>> class A: pass
>>> class B: pass
>>> class C(A, B): pass
クラス A と B を継承するクラス C を定義します。
メソッド解決順序 (MRO) は、クラスの属性を検索するときに基底クラスを調べる順序です。 Python がクラスの MRO を決める方法は Python 2.3 のメソッド解決順序 を参照してください。
多重継承が常に認められるわけではありません。 基底クラスのいずれかがサブクラス化を認めない場合、一貫した MRO を作れない場合、有効なメタクラスを決められない場合、インスタンスのレイアウトが衝突する場合には、多重継承するクラスを定義しようとするとエラーを送出します。 以下で順に説明します。
まず、すべての基底クラスがサブクラス化を認めていなければなりません。
ほとんどのクラスはサブクラス化を認めますが、bool など、一部の組み込みクラスは認めません:
>>> class SubBool(bool): # TypeError
... pass
Traceback (most recent call last):
...
TypeError: type 'bool' is not an acceptable base type
クラスの MRO では、そのクラスの基底クラスは、基底クラスリストに指定した順に並びます。 また、子クラスは必ずそのすべての基底クラスより前に並びます。 指定された基底クラスのリストから、これらの規則を満たす一貫した MRO を解決できない場合、クラス定義は失敗します:
>>> class Base: pass
>>> class Child(Base): pass
>>> class Grandchild(Base, Child): pass # TypeError
Traceback (most recent call last):
...
TypeError: Cannot create a consistent method resolution order (MRO) for bases Base, Child
Grandchild の MRO では、Base は基底クラスリストの先頭なので Child より前に並ぶ必要があります。
しかし、Child の親でもあるので Child より後に並ぶ必要もあります。
これは矛盾するため、クラスを定義できません。
基底クラスの一部が独自の メタクラス を持つ場合、作成するクラスのメタクラスは、基底クラスのメタクラスと、子クラスに明示的に指定したメタクラスの中から選びます。 選ぶメタクラスは、他のすべての候補のサブクラスでなければなりません。 候補の中にそのようなメタクラスがなければ、適切なメタクラスの決定 で説明しているとおり、クラスを作成できません。
最後に、基底クラスのインスタンスのレイアウトに互換性がなければなりません。 これは、そのクラスの solid base を計算できなければならないという意味です。 どのクラスが solid base であるかは Python の実装によって異なります。
CPython 実装の詳細: In CPython, a class is a solid base if it has a
nonempty __slots__ definition.
Many but not all classes defined in C are also solid bases, including most
builtins (such as int or BaseException)
but excluding most concrete Exception classes. Generally, a C class
is a solid base if its underlying struct is different in size from its base class.
Every class has a solid base. object, the base class, has itself as its solid base.
If there is a single base, the child class's solid base is that class if it is a solid base,
or else the base class's solid base. If there are multiple bases, we first find the solid base
for each base class to produce a list of candidate solid bases. If there is a unique solid base
that is a subclass of all others, then that class is the solid base. Otherwise, class creation
fails.
例:
>>> class Solid1:
... __slots__ = ("solid1",)
>>>
>>> class Solid2:
... __slots__ = ("solid2",)
>>>
>>> class SolidChild(Solid1):
... __slots__ = ("solid_child",)
>>>
>>> class C1: # solid base は `object`
... pass
>>>
>>> # OK: solid base は `Solid1` と `object` で、`Solid1` は `object` のサブクラス。
>>> class C2(Solid1, C1): # solid base は `Solid1`
... pass
>>>
>>> # OK: solid base は `SolidChild` と `Solid1` で、`SolidChild` は `Solid1` のサブクラス。
>>> class C3(SolidChild, Solid1): # solid base は `SolidChild`
... pass
>>>
>>> # エラー: solid base は `Solid1` と `Solid2` で、どちらも他方のサブクラスではない。
>>> class C4(Solid1, Solid2): # エラー: solid base が一つに決まらない
... pass
Traceback (most recent call last):
...
TypeError: multiple bases have instance lay-out conflict
8.9. コルーチン¶
Added in version 3.5.
8.9.1. コルーチン関数定義¶
async_funcdef: [decorators] "async" "def"funcname"(" [parameter_list] ")" ["->"expression] ":"suite
Python のコルーチンの実行は、多くの箇所で一時停止して再開できます (coroutine を参照)。
await 式、async for、async 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 と async がキーワードになりました。
以前は、コルーチン関数の本体の中でのみキーワードとして扱われていました。
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).__aiter__()
running = True
while running:
try:
TARGET = await iter.__anext__()
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 = manager.__aenter__
aexit = manager.__aexit__
value = await aenter()
hit_except = False
try:
TARGET = value
SUITE
except:
hit_except = True
if not await aexit(*sys.exc_info()):
raise
finally:
if not hit_except:
await aexit(None, None, None)
ただし、__aenter__() と __aexit__() には、暗黙の 特殊メソッドの検索 を使います。
コルーチン関数の本体の外で async with 文を使用すると SyntaxError になります。
参考
- PEP 492 - async 構文および await 構文付きのコルーチン
コルーチンを Python のまともな独り立ちした概念にし、サポートする構文を追加した提案。
8.10. 型パラメータリスト¶
Added in version 3.12.
バージョン 3.13 で変更: デフォルト値をサポートしました (PEP 696 を参照)。
type_params: "["type_param(","type_param)* "]" type_param:typevar|typevartuple|paramspectypevar:identifier(":"expression)? ("="expression)? typevartuple: "*"identifier("="expression)? paramspec: "**"identifier("="expression)?
関数 (コルーチン を含む)、クラス、型エイリアス には型パラメータリストを指定できます。
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]
これは、その関数、クラス、型エイリアスが、型変数に関してジェネリックであることを意味します。 この情報を主に使うのは静的型チェッカーで、実行時にはジェネリックなオブジェクトは対応する非ジェネリックなものとほぼ同じように動作します。
型パラメータは、関数、クラス、型エイリアスの名前の直後に、角括弧 ([]) で囲んで宣言します。
型パラメータにはジェネリックなオブジェクトのスコープ内でアクセスできますが、それ以外の場所ではアクセスできません。
そのため、def func[T](): pass と宣言しても、モジュールスコープでは名前 T を使えません。
以下では、ジェネリックなオブジェクトの意味をより正確に説明します。
型パラメータのスコープは、ジェネリックなオブジェクトの作成を包む特殊な関数 (厳密には アノテーションスコープ) でモデル化されます。
ジェネリックな関数、クラス、型エイリアスは、型パラメータを列挙した __type_params__ 属性を持ちます。
型パラメータには三つの種類があります:
typing.TypeVar: 単純な名前 (例:T) で導入します。 型チェッカーに対して単一の型を表します。typing.TypeVarTuple: 一つのアスタリスクを前に付けた名前 (例:*Ts) で導入します。 任意の数の型からなるタプルを表します。typing.ParamSpec: 二つのアスタリスクを前に付けた名前 (例:**P) で導入します。 呼び出し可能オブジェクトの仮引数を表します。
typing.TypeVar の宣言では、コロン (:) の後に式を記述して、上限 や 制約 を定義できます。
コロンの後の単一の式は上限を表します (例: T: int)。
これは、typing.TypeVar が、その上限のサブタイプだけを表せることを意味します。
コロンの後の、丸括弧で囲んだ式のタプルは、制約の集合を表します (例: T: (str, bytes))。
タプルの各要素は型でなければなりません (ただし、これも実行時には強制されません)。
制約付きの型変数が取れるのは、制約のリストにある型のいずれかだけです。
型パラメータリストの構文で宣言した typing.TypeVar では、ジェネリックなオブジェクトの作成時には上限と制約を評価しません。
__bound__ 属性や __constraints__ 属性を通じて明示的に値にアクセスしたときに初めて評価します。
これを実現するため、上限や制約は独立した アノテーションスコープ 内で評価します。
typing.TypeVarTuple と typing.ParamSpec には、上限や制約を指定できません。
三種類すべての型パラメータに、その型パラメータを明示的に指定しなかった場合に使う デフォルト値 も指定できます。
一つの等号 (=) と式を後に付けて指定します。
型変数の上限や制約と同様に、デフォルト値はオブジェクトの作成時には評価せず、型パラメータの __default__ 属性にアクセスしたときに初めて評価します。
そのため、デフォルト値は独立した アノテーションスコープ 内で評価します。
型パラメータにデフォルト値を指定しなければ、__default__ 属性は特別な番兵オブジェクト typing.NoDefault になります。
次の例は、指定できる型パラメータ宣言のすべての種類を示しています。
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. ジェネリック関数¶
ジェネリック関数は次のように宣言します。
def func[T](arg: T): ...
この構文は、次のコードと等価です。
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()
ここで annotation-def は アノテーションスコープ を表し、実行時には実際にはどの名前にも束縛されません。
この書き換えでは、もう一つ簡略化しています。
この構文は typing モジュールの属性アクセスを経由せず、typing.TypeVar のインスタンスを直接作成します。
ジェネリック関数のアノテーションは、型パラメータの宣言に使うアノテーションスコープ内で評価します。 ただし、関数のデフォルト値とデコレータは、そのスコープ内では評価しません。
次の例は、これらの場合や、その他の種類の型パラメータについて、スコープの規則を示します。
@decorator
def func[T: int, *Ts, **P](*args: *Ts, arg: Callable[P, T] = some_default):
...
TypeVar の上限の 遅延評価 を除き、これは次のコードと等価です。
DEFAULT_OF_arg = some_default
annotation-def TYPE_PARAMS_OF_func():
annotation-def BOUND_OF_T():
return int
# 実際には BOUND_OF_T() は必要なときにだけ評価する。
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())
DEFAULT_OF_arg のような大文字を使った名前は、実行時には実際には束縛されません。
8.10.2. ジェネリッククラス¶
ジェネリッククラスは次のように宣言します。
class Bag[T]: ...
この構文は、次のコードと等価です。
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()
ここでも、annotation-def (実際のキーワードではありません) は アノテーションスコープ を表します。
名前 TYPE_PARAMS_OF_Bag は、実行時には実際には束縛されません。
ジェネリッククラスは暗黙に typing.Generic を継承します。
ジェネリッククラスの基底クラスとキーワード引数は、型パラメータの型スコープ内で評価し、デコレータはそのスコープの外で評価します。
次の例で示します。
@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. ジェネリックな型エイリアス¶
type 文は、ジェネリックな型エイリアスの作成にも使えます。
type ListOrSet[T] = list[T] | set[T]
値の 遅延評価 を除き、これは次のコードと等価です。
annotation-def TYPE_PARAMS_OF_ListOrSet():
T = typing.TypeVar("T")
annotation-def VALUE_OF_ListOrSet():
return list[T] | set[T]
# 実際には値は遅延評価する
return typing.TypeAliasType("ListOrSet", VALUE_OF_ListOrSet(), type_params=(T,))
ListOrSet = TYPE_PARAMS_OF_ListOrSet()
ここで annotation-def (実際のキーワードではありません) は アノテーションスコープ を表します。
TYPE_PARAMS_OF_ListOrSet のような大文字を使った名前は、実行時には実際には束縛されません。
8.11. アノテーション¶
バージョン 3.14 で変更: アノテーションがデフォルトで遅延評価されるようになりました。
変数と関数の仮引数には、名前の後にコロンと式を付けて アノテーション を指定できます。
x: annotation = 1
def f(param: annotation): ...
関数には、矢印の後に戻り値のアノテーションを指定することもできます。
def f() -> annotation: ...
アノテーションは慣習的に 型ヒント に使われますが、言語がそれを強制するわけではなく、一般には任意の式を含められます。
dataclasses や @functools.singledispatch のように、アノテーションを調べて利用する仕組みを使わない限り、アノテーションの有無はコードの実行時の意味を変えません。
デフォルトでは、アノテーションは アノテーションスコープ 内で遅延評価されます。
つまり、アノテーションを含むコードを評価するときには、アノテーションを評価しません。
代わりにインタープリタは、後で必要になったときにアノテーションを評価するための情報を保存します。
annotationlib モジュールには、アノテーションを評価するためのツールが用意されています。
future 文 from __future__ import annotations がある場合は、代わりにすべてのアノテーションを文字列として保存します。
>>> from __future__ import annotations
>>> def f(param: annotation): ...
>>> f.__annotations__
{'param': 'annotation'}
この future 文は将来の Python で非推奨となり、削除される予定ですが、Python 3.13 のサポート終了より前には行われません (PEP 749 を参照)。
この文を使うと、annotationlib.get_annotations() や typing.get_type_hints() などのイントロスペクションツールが実行時にアノテーションを解決できる可能性は低くなります。
脚注