7. 単純文 (simple statement)¶
単純文とは、単一の論理行内に収められる文です。単一の行内には、複数の単純文をセミコロンで区切って入れることができます。単純文の構文は以下の通りです:
simple_stmt:expression_stmt|assert_stmt|assignment_stmt|augmented_assignment_stmt|annotated_assignment_stmt|pass_stmt|del_stmt|return_stmt|yield_stmt|raise_stmt|break_stmt|continue_stmt|import_stmt|future_stmt|global_stmt|nonlocal_stmt|type_stmt
7.1. 式文 (expression statement)¶
式文は、(主に対話的な使い方では) 値を計算して出力するために使ったり、(通常は) プロシジャ (procedure: 有意な結果を返さない関数のことです; Python では、プロシジャは値 None を返します) を呼び出すために使います。その他の使い方でも式文を使うことができますし、有用なこともあります。式文の構文は以下の通りです:
expression_stmt: starred_expression
式文は式のリスト (単一の式のこともあります) を値評価します。
対話モードでは、値が None でなければ、値を組み込み関数 repr() で文字列に変換して、その結果の文字列を標準出力に一行使って書き出します。 (None になる式文の値は書き出されないので、プロシジャの呼び出しを行っても出力は得られません。)
7.2. 代入文 (assignment statement)¶
代入文は、名前を値に (再) 束縛したり、変更可能なオブジェクトの属性や要素を変更したりするために使われます:
assignment_stmt: (target_list"=")+ (starred_expression|yield_expression) target_list:target(","target)* [","] target:identifier| "(" [target_list] ")" | "[" [target_list] "]" |attributeref|subscription| "*"target
(attributeref と subscription の構文定義は プライマリ 節を参照してください。)
代入文は式リストを評価し、結果として得られた一つのオブジェクトを、各ターゲットリストに左から右へ代入します。 式リストは単一の式の場合も、カンマで区切った式のリストの場合もあり、後者はタプルになります。
代入は、ターゲット (またはターゲットリスト) の形式に応じて再帰的に定義されます。 ターゲットがミュータブルなオブジェクトの一部 (属性参照や添字参照) の場合、最終的にはそのオブジェクトが代入を実行し、妥当性を判断します。 代入を受け付けられなければ例外を送出することがあります。 各型の規則と送出する例外は、オブジェクト型の定義に記載されています (標準型の階層 節を参照)。
ターゲットリストは、丸括弧や角括弧で囲まれていてもよく、それに対するオブジェクトの代入は、以下のように再帰的に定義されています。
ターゲットリストのターゲットが1つだけでコンマが続いておらず、任意に丸括弧で囲われている場合、オブジェクトはそのターゲットに代入されます。
その他:
"星付き"のターゲットと呼ばれる、頭にアスタリスクが一つ付いたターゲットがターゲットリストに一つだけ含まれている場合: オブジェクトはイテラブルで、少なくともターゲットリストのターゲットの数よりも一つ少ない要素を持たなければなりません。 星付きのターゲットより前のターゲットに、イテラブルの先頭の要素が左から右へ代入されます。 星付きのターゲットより後ろのターゲットに、イテラブルの末尾の要素が代入されます。 星付きのターゲットに、イテラブルの残った要素のリストが代入されます (リスト空でもかまいません)。
そうでない場合: オブジェクトは、ターゲットリストのターゲットと同じ数の要素を持つイテラブルでなければならず、要素は左から右へ対応するターゲットに代入されます。
単一のターゲットへの単一のオブジェクトの代入は、以下のようにして再帰的に定義されています。
ターゲットが識別子 (名前) の場合:
名前が現在のコードブロック内の
globalやnonlocal文に書かれていないければ: 名前は現在のローカル名前空間内のオブジェクトに束縛されます。そうでなければ: 名前はそれぞれグローバル名前空間内か、
nonlocalで決められた外側の名前空間内のオブジェクトに束縛されます。
名前がすでに束縛済みの場合、再束縛 (rebind) がおこなわれます。再束縛によって、以前その名前に束縛されていたオブジェクトの参照カウント (reference count) がゼロになった場合、オブジェクトは解放 (deallocate) され、デストラクタ (destructor) が (存在すれば) 呼び出されます。
ターゲットが属性参照の場合: 参照されている一次語の式が値評価されます。値は代入可能な属性を伴うオブジェクトでなければなりません; そうでなければ、
TypeErrorが送出されます。次に、このオブジェクトに対して、被代入オブジェクトを指定した属性に代入してよいか問い合わせます; 代入を実行できない場合、例外 (通常はAttributeErrorですが、必然ではありません) を送出します。注意: オブジェクトがクラスインスタンスで、代入演算子の両辺に属性参照があるとき、右辺式の
a.xはインスタンスの属性と (インスタンスの属性が存在しなければ) クラス属性のどちらにもアクセスする可能性があります。左辺のターゲットa.xは常にインスタンスの属性として割り当てられ、必要ならば生成されます。このとおり、現れる二つのa.xは同じ値を参照するとは限りません: 右辺式はクラス属性を参照し、左辺は新しいインスタンス属性を代入のターゲットとして生成するようなとき:class Cls: x = 3 # クラス変数 inst = Cls() inst.x = inst.x + 1 # Cls.x は 3 のままで、inst.x を 4 にする
この説明は、
@propertyで作成したプロパティなどのデスクリプタ属性には当てはまらない場合があります。ターゲットが添字参照の場合、まず参照の一次語の式を評価します。 次に添字の式を評価します。 その後、添字と代入するオブジェクトの二つを引数として、一次語の
__setitem__()メソッドを呼び出します。通常、
__setitem__()はリストなどのミュータブルなシーケンスオブジェクトや、辞書などのマッピングオブジェクトに定義され、以下のように動作します。一次語が (リストのような) ミュータブルなシーケンスオブジェクトであれば、添字表記は整数を与えなければなりません。整数が負なら、シーケンスの長さが加算されます。整数は最終的に、シーケンスの長さよりも小さな非負の整数でなくてはならず、シーケンスは、そのインデクスに持つ要素に被代入オブジェクトを代入してよいか問い合わせられます。インデクスが範囲外なら、
IndexErrorが送出されます (添字指定されたシーケンスに代入を行っても、リスト要素の新たな追加はできません)。一次語が辞書などのマッピングオブジェクトの場合、添字の型はマッピングのキーの型と互換性がなければなりません。 次に、その添字を代入するオブジェクトに対応付けるキーと値のペアを作るよう、マッピングに要求します。 同じキーの値を持つ既存のペアを置き換えるか、同じ値のキーがなければ新しいペアを挿入します。
ターゲットがスライスの場合、一次語の式はリストなどのミュータブルなシーケンスオブジェクトに評価されなければなりません。 代入するオブジェクトは イテラブル でなければなりません。 スライスの下限と上限は整数でなければならず、
Noneまたは省略の場合のデフォルト値は、それぞれゼロとシーケンスの長さです。 いずれかの境界値が負なら、その値にシーケンスの長さを加えます。 結果の境界値は、ゼロ以上シーケンスの長さ以下の範囲に収められます。 最後に、シーケンスオブジェクトに対して、スライスを代入するシーケンスの要素で置き換えるよう要求します。 スライスの長さと代入するシーケンスの長さは異なっていても構いません。 その場合、代入先のシーケンスが許容すれば、その長さが変わります。
代入の定義によれば、左辺と右辺のオーバーラップは '同時 (simultaneous)' です (例えば a, b = b, a は二つの変数を入れ替えます) が、代入対象となる変数群 どうし のオーバーラップは左から右へ起こり、混乱の元です。例えば、以下のプログラムは [0, 2] を出力してしまいます:
x = [0, 1]
i = 0
i, x[i] = 1, 2 # i を更新し、その後 x[i] を更新する
print(x)
参考
- PEP 3132 - Extended Iterable Unpacking
*targetの指定機能。
7.2.1. 累算代入文 (augmented assignment statement)¶
累算代入文は、二項演算と代入文を組み合わせて一つの文にしたものです:
augmented_assignment_stmt:augtargetaugop(expression_list|yield_expression) augtarget:identifier|attributeref|subscriptionaugop: "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**=" | ">>=" | "<<=" | "&=" | "^=" | "|="
(最後の3つの構文定義については プライマリ を参照してください。)
累算代入文は、ターゲット (通常の代入文と違って、アンパックは起こりません) と式リストを評価し、それら二つの被演算子間で特定の累算代入型の二項演算を行い、結果をもとのターゲットに代入します。ターゲットは一度しか評価されません。
x += 1 のような累算代入文は、x = x + 1 と書き換えて似た効果を得られますが、まったく同じではありません。
累算代入では x を一度しか評価しません。
また、可能な場合は インプレース で演算を行います。
つまり、新しいオブジェクトを作成してターゲットに代入する代わりに、既存のオブジェクトを変更します。
通常の代入とは違い、累算代入文は右辺を評価する 前に 左辺を評価します。たとえば、a[i] += f(x) はまず a[i] を調べ、f(x) を評価して加算を行い、最後に結果を a[i] に割り当てます。
累算代入文で行われる代入は、タプルへの代入や、一文中に複数のターゲットが存在する場合を除き、通常の代入と同じように扱われます。同様に、累算代入で行われる二項演算は、場合によって インプレース演算 が行われることを除き、通常の二項演算と同じです。
ターゲットが属性参照の場合、通常の代入と同じ クラス属性とインスタンス属性に関する注意点 が当てはまります。
7.2.2. 注釈付き代入文 (annotated assignment statements)¶
注釈 代入は、1 つの文の中で変数や属性のアノテーションとオプションの代入文を組み合わせたものです:
annotated_assignment_stmt:augtarget":"expression["=" (starred_expression|yield_expression)]
通常の 代入文 (assignment statement) との違いは、代入先が 1 つに限定されることだけです。
代入先が、丸括弧で囲まれていない単一の名前である場合、その代入先は「単純」と見なされます。
クラスまたはモジュールのスコープにある単純な代入先については、アノテーションが遅延評価される アノテーションスコープ に集められます。
アノテーションは、クラスやモジュールの __annotations__ 属性、または annotationlib モジュールの機能を使って評価できます。
代入先が単純でない場合 (属性、添字ノード、丸括弧で囲まれた名前の場合)、アノテーションは評価されません。
関数スコープで名前に注釈が付いていた場合は、その名前はその関数スコープでローカルなものになります。 注釈は絶対に評価されず、関数スコープにも格納されません。
右辺がある場合、注釈付き代入はアノテーションがない場合と同じように実際の代入を行います。
式を代入先とし、右辺がない場合、インタープリタは最後の __setitem__() または __setattr__() の呼び出しを除いて代入先を評価します。
参考
バージョン 3.8 で変更: 注釈付き代入の右辺で、通常の代入と同じ式を使えるようになりました。 以前は、丸括弧で囲まないタプル式など、一部の式が構文エラーになっていました。
バージョン 3.14 で変更: アノテーションを、独立した アノテーションスコープ で遅延評価するようになりました。 代入先が単純でない場合、アノテーションは評価されません。
7.3. assert 文¶
assert 文は、プログラム内にデバッグ用アサーション (debugging assertion) を仕掛けるための便利な方法です:
assert_stmt: "assert"expression[","expression]
単純な形式 assert expression は、次のコードと等価です。
if __debug__:
if not expression: raise AssertionError
拡張形式 assert expression1, expression2 は、次のコードと等価です。
if __debug__:
if not expression1: raise AssertionError(expression2)
これらの等価性は、__debug__ と AssertionError が、それぞれ同名の組み込み変数を参照していることを前提としています。
現在の実装では、組み込み変数 __debug__ は通常 True で、最適化を要求した場合 (コマンドラインオプション -O) は False です。
現在のコード生成器は、コンパイル時に最適化を要求すると assert 文に対してコードを生成しません。
失敗した式のソースコードはスタックトレースの一部として表示されるため、エラーメッセージに含める必要はありません。
__debug__ への代入は不正な操作です。組み込み変数の値は、インタプリタが開始するときに決定されます。
7.4. pass 文¶
pass_stmt: "pass"
pass はヌル操作 (null operation) です --- pass が実行されても、何も起きません。 pass は、構文法的には文が必要だが、コードとしては何も実行したくない場合のプレースホルダとして有用です。例えば:
def f(arg): pass # (今のところ) 何もしない関数
class C: pass # (今のところ) メソッドを持たないクラス
7.5. del 文¶
del_stmt: "del" target_list
オブジェクトの削除 (deletion) は、代入の定義と非常に似た方法で再帰的に定義されています。ここでは完全な詳細は記述せず、いくつかのヒントを述べるにとどめます。
ターゲットリストに対する削除は、各々のターゲットを左から右へと順に再帰的に削除します。
Deletion of a name removes the binding of that name from the local or global
namespace, depending on whether the name occurs in a global statement
in the same code block. Trying to delete an unbound name raises a
NameError exception.
属性参照や添字参照の削除は、対象の一次語オブジェクトに委ねられます。 スライスの削除は、通常は適切な型の空のスライスを代入するのと等価です (ただし、この動作もスライス対象のオブジェクトが決めます)。
バージョン 3.2 で変更: 以前は、ある名前がネストしたブロックの自由変数として表れる場合は、ローカル名前空間からその名前を削除することは不正な処理でした。
7.6. return 文¶
return_stmt: "return" [expression_list]
return は、関数定義内で構文法的にネストして現れますが、ネストしたクラス定義内には現れません。
式リストがある場合、リストが値評価されます。それ以外の場合は None で置き換えられます。
return を使うと、式リスト (または None) を戻り値として、現在の関数呼び出しから抜け出します。
return によって、 finally 節をともなう try 文の外に処理が引き渡されると、実際に関数から抜ける前に finally 節が実行されます。
ジェネレータ関数では、 return 文はジェネレータの終わりを示し、 StopIteration 例外を送出させます。返された値は (あれば)、 StopIteration を構成する引数に使われ、 StopIteration.value 属性になります。
非同期ジェネレータ関数では、引数無しの return 文は非同期ジェネレータの終わりを示し、 StopAsyncIteration を送出させます。
引数ありの return 文は、非同期ジェネレータ関数では文法エラーです。
7.7. yield 文¶
yield_stmt: yield_expression
yield 文は、意味的には yield 式 と等価です。
yield 文を使うと、等価な yield 式の式文で必要になる丸括弧を省けます。
例えば、次の yield 文について考えます。
yield <expr>
yield from <expr>
は以下の yield 式文と等価です
(yield <expr>)
(yield from <expr>)
yield 式と yield 文は ジェネレータ 関数を定義するときだけ使い、ジェネレータ関数の本体の中にだけ記述します。
関数定義で yield を使うだけで、その定義は通常の関数ではなくジェネレータ関数を作成するようになります。
7.8. raise 文¶
raise_stmt: "raise" [expression["from"expression]]
式がない場合、raise は現在処理中の例外を再送出します。
この例外は アクティブな例外 とも呼ばれます。
現在アクティブな例外がない場合は、それがエラーであることを示す RuntimeError を送出します。
そうでなければ、 raise は最初の式を、例外オブジェクトとして評価します。これは、 BaseException のサブクラスまたはインスタンスでなければなりません。クラスなら、例外インスタンスが必要なとき、クラスを無引数でインスタンス化することで得られます。
例外の 型 は例外インスタンスのクラスで、 値 はインスタンスそのものです。
通常、例外を送出するとトレースバックオブジェクトが自動的に作られ、例外の __traceback__ 属性に設定されます。
例外の with_traceback() メソッドを使うと、例外の作成と独自のトレースバックの設定を一度に行えます。
このメソッドは、引数の値をトレースバックとして設定した、同じ例外インスタンスを返します。
次のように使います。
raise Exception("foo occurred").with_traceback(tracebackobj)
from 節は例外の連鎖に使います。
指定する場合、二つ目の expression は別の例外クラスか例外インスタンスでなければなりません。
二つ目の式が例外インスタンスの場合、送出する例外の __cause__ 属性 (書き換え可能) に設定されます。
式が例外クラスの場合、そのクラスをインスタンス化し、得られた例外インスタンスを送出する例外の __cause__ 属性に設定します。
送出した例外を処理しなければ、両方の例外が表示されます:
>>> try:
... print(1 / 0)
... except Exception as exc:
... raise RuntimeError("Something bad happened") from exc
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
print(1 / 0)
~~^~~
ZeroDivisionError: division by zero
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
raise RuntimeError("Something bad happened") from exc
RuntimeError: Something bad happened
すでに例外を処理している最中に新たな例外を送出した場合も、同様の仕組みが暗黙に働きます。
except 節、finally 節、with 文を使うと、例外を処理することがあります。
このとき、元の例外は新たな例外の __context__ 属性に設定されます:
>>> try:
... print(1 / 0)
... except:
... raise RuntimeError("Something bad happened")
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
print(1 / 0)
~~^~~
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
raise RuntimeError("Something bad happened")
RuntimeError: Something bad happened
from 節に None を指定すると、例外の連鎖を明示的に抑制できます:
>>> try:
... print(1 / 0)
... except:
... raise RuntimeError("Something bad happened") from None
...
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened
例外に関する追加情報は 例外 節にあります。また、例外処理に関する情報は try 文 節にあります。
バージョン 3.3 で変更: None が raise X from Y の Y として使えるようになりました。
例外のコンテキストの自動表示を抑制する __suppress_context__ 属性が追加されました。
バージョン 3.11 で変更: except 節でアクティブな例外のトレースバックを変更した場合、その後の raise 文は変更後のトレースバックで例外を再送出するようになりました。
以前は、捕捉した時点のトレースバックで例外を再送出していました。
7.9. break 文¶
break_stmt: "break"
break 文は、構文としては for ループや while ループの内側でのみ出現することができますが、ループ内の関数定義やクラス定義の内側には出現できません。
break 文は、文を囲う最も内側のループを終了させ、ループにオプションの else 節がある場合にはそれをスキップします。
for ループを break によって終了すると、ループ制御ターゲットはその時の値を保持します。
break が finally 節を伴う try 文の外側に処理を渡す際には、ループを実際に抜ける前にその finally 節が実行されます。
7.10. continue 文¶
continue_stmt: "continue"
continue 文は for ループや while ループ内のネストで構文法的にのみ現れますが、ループ内の関数定義やクラス定義の中には現れません。 continue 文は、文を囲う最も内側のループの次の周期に処理を継続します。
continue が finally 句を持った try 文を抜けるとき、その finally 句が次のループサイクルを始める前に実行されます。
7.11. import 文¶
import_stmt: ["lazy"] "import"module["as"identifier] (","module["as"identifier])* | ["lazy"] "from"relative_module"import"identifier["as"identifier] (","identifier["as"identifier])* | ["lazy"] "from"relative_module"import" "("identifier["as"identifier] (","identifier["as"identifier])* [","] ")" | "from"relative_module"import" "*" module: (identifier".")*identifierrelative_module: "."*module| "."+
(from 節が無い) 基本の import 文は 2 つのステップで実行されます:
モジュールを見付け出し、必要であればロードし初期化する
import文があるスコープの現在の名前空間に、名前を一つ以上定義する。 これは代入文と同様で、globalとnonlocalの意味も適用される。
文が (カンマで区切られた) 複数の節を含んでいるときは、ちょうどその節が個別の import 文に分割されたかのように、2つのステップが節ごとに個別に実行されます。
モジュールを見付け、ロードする 1 つ目のステップの詳細については、 インポートシステム の節により詳しく書かれています。そこでは、インポートシステムの動作をカスタマイズするのに使える全てのフックの仕組みだけでなく、様々な種類のインポートできるパッケージとモジュールについても解説されています。このステップが失敗するということは、おそらくモジュールが見付からないか、 あるいは モジュールにあるコードの実行を含め、モジュールの初期化の途中でエラーが起きるかのどちらかが起きていることに注意してください。
要求したモジュールが無事に取得できた場合、次の 3 つのうちの 1 つの方法でローカル名前空間で使えるようになります:
モジュール名の後に
asが続いていた場合は、asの後ろの名前を直接、インポートされたモジュールが束縛します。他の名前が指定されておらず、インポートされているモジュールが最上位のモジュールだった場合、そのモジュール名がインポートされたモジュールへの参照として、ローカル名前空間で束縛されます
インポートされているモジュールが最上位のモジュール でない 場合、モジュールを含む最上位のパッケージ名が、そのパッケージへの参照として、ローカル名前空間で束縛されます。インポートされたモジュールには、直接ではなく完全修飾名を使ってアクセスしなければなりません
from 形式ではもう少し複雑な手順を踏みます:
from節で指定されたモジュールを見付け出し、必要であればロードし初期化する;import節で指定されたそれぞれの識別子に対し以下の処理を行う:インポートされたモジュールがその識別子名の属性を持っているかを確認する
その識別子名の属性を持っていなかった場合は、その識別子名でサブモジュールのインポートを試み、インポートされたモジュールにその属性があるか再度確認する
属性が見付からない場合は、
ImportErrorを送出する。属性が見付かった場合、その値への参照を現在の名前空間に格納する。
as節があればその名前を使い、なければ属性名を使う。
例:
import foo # foo をインポートし、ローカルに束縛する
import foo.bar.baz # foo、foo.bar、foo.bar.baz をインポートし、foo をローカルに束縛する
import foo.bar.baz as fbb # foo、foo.bar、foo.bar.baz をインポートし、foo.bar.baz を fbb に束縛する
from foo.bar import baz # foo、foo.bar、foo.bar.baz をインポートし、foo.bar.baz を baz に束縛する
from foo import attr # foo をインポートし、foo.attr を attr に束縛する
識別子のリストが星 ('*') に置き換わっている場合は、モジュールで定義されている公開された全ての名前が、 import 文がいるスコープのローカル名前空間に束縛されます。
モジュールが定義する 公開名 は、そのモジュールの名前空間にある __all__ という変数を調べて決定します。
定義されている場合、__all__ は、そのモジュールが定義またはインポートした名前を表す文字列のシーケンスでなければなりません。
非 ASCII 文字を含む名前は normalization form NFKC でなければなりません。
詳しくは 名前に含まれる非 ASCII 文字 を参照してください。
__all__ に指定した名前はすべて公開名と見なされ、実在しなければなりません。
__all__ が定義されていない場合、公開名はモジュールの名前空間にある、アンダースコア ('_') で始まらないすべての名前です。
__all__ には公開 API 全体を含めるべきです。
これは、モジュール内で使うためにインポートしたライブラリモジュールなど、API の一部ではないものを誤って公開しないようにするためのものです。
インポートのワイルドカード形式 --- from module import * --- は、モジュールレベルでのみ許されます。クラスや関数定義でこの形式を使おうとすると、 SyntaxError が送出されます。
インポートするモジュールは、必ずしも絶対名で指定する必要はありません。
モジュールやパッケージが他のパッケージに含まれている場合、同じ最上位パッケージ内では、パッケージ名を明記せずに相対インポートできます。
from の後に指定するモジュール名やパッケージ名の先頭にドットを付けることで、正確な名前を指定せずに、現在のパッケージ階層からいくつ上に移るかを指定できます。
ドット一つは、インポートを行うモジュールが属する現在のパッケージを表します。
ドット二つなら一階層上、三つなら二階層上を表し、以降も同様です。
例えば、pkg パッケージ内のモジュールで from . import mod を実行すると pkg.mod をインポートします。
pkg.subpkg1 内で from ..subpkg2 import mod を実行すると pkg.subpkg2.mod をインポートします。
相対インポートの仕様は パッケージの相対インポート 節を参照してください。
読み込むモジュールを動的に決めるアプリケーションのために、importlib.import_module() が用意されています。
引数 module、filename、sys.path、sys.meta_path、sys.path_hooks とともに、監査イベント import を発生させます。
7.11.1. 遅延インポート¶
lazy キーワードは ソフトキーワード で、import 文または from 文の直前にあるときだけ特別な意味を持ちます。
インポート文の前に lazy キーワードを付けると、そのインポートは 遅延 され、インポート文の位置ではモジュールを直ちに読み込みません。
代わりに遅延プロキシオブジェクトを作成し、その名前に束縛します。
実際のモジュールは、その名前を初めて使ったときに読み込まれます。
遅延インポートはモジュールスコープでのみ使えます。
関数、クラス本体、try/except/finally ブロックの中で lazy を使うと、SyntaxError を送出します。
星付きインポートは遅延できず、lazy from module import * は構文エラーです。
また、future 文 も遅延できません。
lazy from ... import では、インポートする各名前を遅延プロキシオブジェクトに束縛します。
これらの名前のいずれかに初めてアクセスするとモジュール全体を読み込みますが、実際の値に解決するのはアクセスした名前だけです。
他の名前は、アクセスするまで遅延プロキシのままです。
以下はプログラム例です:
lazy import json
import sys
print('json' in sys.modules) # False - json モジュールはまだ読み込まれていない
# 初めて使うときに読み込まれる
result = json.dumps({"hello": "world"})
print('json' in sys.modules) # True - 読み込み済み
モジュールの読み込み中に ImportError や SyntaxError などのエラーが起きた場合、インポート文自体ではなく、遅延インポートしたものを初めて使った箇所で送出されます。
遅延インポートの完全な仕様は PEP 810 を参照してください。
Added in version 3.15.
7.11.1.1. __lazy_modules__ による互換性の確保¶
lazy キーワードを使う代わりに、モジュールレベルの __lazy_modules__ 変数を定義して、特定のインポートを遅延読み込みにできます。
この変数を定義する場合、完全修飾モジュール名の文字列を含むコンテナでなければなりません。
モジュールスコープにある通常の (lazy でない) import 文の対象が __lazy_modules__ に含まれていれば、lazy キーワードを使った場合と同じように遅延インポートとして扱います。
これにより、個々の import 文を変更せずに、特定の依存先を遅延読み込みにできます。
Python 3.15 より前のバージョンをサポートしつつ、3.15 以降では遅延インポートを使う場合に便利です。
__lazy_modules__ = ["json", "pathlib"]
import json # 遅延読み込み (名前が __lazy_modules__ に含まれる)
import os # 即時読み込み (名前が __lazy_modules__ に含まれない)
import pathlib # 遅延読み込み
相対インポートは、検索前に絶対名に解決されます。
そのため、__lazy_modules__ には常に完全修飾モジュール名を含めなければなりません。
from 形式のインポートで対象となる名前は、メンバーの名前ではなく from の後にあるモジュールです。
# mypackage/mymodule.py 内
__lazy_modules__ = ["mypackage", "mypackage.sub.utils"]
from . import helper # 遅延読み込み: . は mypackage に解決される
from .sub.utils import func # 遅延読み込み: .sub.utils は mypackage.sub.utils に解決される
import json # 即時読み込み (__lazy_modules__ に含まれない)
関数、クラス本体、try/except/finally ブロックの内部のインポートは、__lazy_modules__ にかかわらず常に即時に行われます。
Added in version 3.15.
7.11.2. future 文 (future statement)¶
future 文 は、将来の特定の新たな機能が標準化された Python のリリースで利用可能になるような構文や意味付けを使って、特定のモジュールをコンパイルさせるための、コンパイラに対する指示句 (directive) です。
future 文は互換性のない変更がされた将来の Python のバージョンに容易に移行するためのものです。future 文によって新機能が標準となるリリースの前にそれをモジュール単位で使用することが出来ます。
future_stmt: "from" "__future__" "import"feature["as"identifier] (","feature["as"identifier])* | "from" "__future__" "import" "("feature["as"identifier] (","feature["as"identifier])* [","] ")" feature:identifier
future 文は、モジュールの先頭周辺に書かなければなりません。 future 文の前に書いてよい内容は以下です :
モジュールのドキュメンテーション文字列 ( あれば )
コメント ,
空行 ,
その他の future 文。
future 文を使う必要がある唯一の機能は annotations です (PEP 563 を参照してください)。
future 文で有効にできる歴史的な機能は、今でも Python 3 が認識します。
そのリストは absolute_import, division, generator_stop, generators, unicode_literals, print_function, nested_scopes, with_statement です。
これらは既に全てが有効になっていて、後方互換性のためだけに残されているため、冗長なだけです。
future 文は、コンパイル時に特別なやり方で認識され、扱われます: 言語の中核をなす構文構成 (construct) に対する意味付けが変更されている場合、変更部分はしばしば異なるコードを生成することで実現されています。新たな機能によって、(新たな予約語のような) 互換性のない新たな構文が取り入れられることさえあります。この場合、コンパイラはモジュールを別のやりかたで解析する必要があるかもしれません。こうしたコード生成に関する決定は、実行時まで先延ばしすることはできません。
これまでの全てのリリースにおいて、コンパイラはどの機能が定義済みかを知っており、 future 文に未知の機能が含まれている場合にはコンパイル時エラーを送出します。
future 文の実行時における直接的な意味付けは、 import 文と同じです。標準モジュール __future__ があり、これについては後で述べます。 __future__ は、 future 文が実行される際に通常の方法で import されます。
future 文の実行時における特別な意味付けは、 future 文で有効化される特定の機能によって変わります。
以下の文には、何ら特殊な意味はないので注意してください:
import __future__ [as name]
これは future 文ではありません; この文は通常の import 文であり、その他の特殊な意味付けや構文的な制限はありません。
future 文を含むモジュール M 内で組み込み関数 exec() や compile() を呼び出してコンパイルしたコードは、デフォルトで、その future 文に対応する新しい構文や意味を使います。
この動作は compile() の省略可能な引数で制御できます。
詳しくは、その関数のドキュメントを参照してください。
対話的インタプリタのプロンプトでタイプ入力した future 文は、その後のインタプリタセッション中で有効になります。インタプリタを -i オプションで起動して実行すべきスクリプト名を渡し、スクリプト中に future 文を入れておくと、新たな機能はスクリプトが実行された後に開始する対話セッションで有効になります。
参考
- PEP 236 - Back to the __future__
__future__ 機構の原案
7.12. global 文¶
global_stmt: "global"identifier(","identifier)*
global 文は、列挙した識別子をグローバルとして解釈させます。
自由変数はグローバル宣言がなくてもグローバル変数を参照できますが、グローバル変数に代入するには global が必要です。
global 文は、現在のスコープ全体 (モジュール、関数本体、クラス定義) に適用されます。
同じスコープ内で、ある変数をグローバル宣言より前に使用したり、その変数に代入したりすると、SyntaxError を送出します。
モジュールレベルではすべての変数がグローバルなので、global 文は効果を持ちません。
ただし、その場合も global 宣言より前に変数を使用したり、その変数に代入したりしてはなりません。
対話プロンプト (REPL) では、この要件は緩和されます。
プログラマのための注意点: global はパーサーに対する指示です。
global 文と同時に解析するコードにだけ適用されます。
特に、組み込み関数 exec() に渡す文字列やコードオブジェクトに含まれる global 文は、その関数呼び出しを 含む コードブロックには影響しません。
また、その文字列内のコードも、関数呼び出しを含むコード内の global 文の影響を受けません。
eval() 関数と compile() 関数についても同様です。
7.13. nonlocal 文¶
nonlocal_stmt: "nonlocal"identifier(","identifier)*
関数やクラスの定義が他の関数の定義の内側にネストしている場合、そのノンローカルスコープは、外側の関数のローカルスコープです。
nonlocal 文は、列挙した識別子がノンローカルスコープですでに束縛された名前を参照するようにします。
これにより、内側のコードから、そのようなノンローカルの識別子を再束縛できます。
複数のノンローカルスコープに同じ名前の束縛がある場合は、最も近い束縛を使います。
どのノンローカルスコープにも名前が束縛されていない場合や、ノンローカルスコープがない場合は、SyntaxError を送出します。
nonlocal 文は、関数やクラス本体のスコープ全体に適用されます。
同じスコープ内で、ある変数を nonlocal 宣言より前に使用したり、その変数に代入したりすると、SyntaxError を送出します。
プログラマのための注意点: nonlocal はパーサーに対する指示で、同時に解析するコードにだけ適用されます。
global 文の注意点を参照してください。
7.14. type 文¶
type_stmt: 'type'identifier[type_params] "="expression
type 文は、typing.TypeAliasType のインスタンスである型エイリアスを宣言します。
例えば、次の文は型エイリアスを作成します。
type Point = tuple[float, float]
このコードは、おおむね次のコードと等価です。
annotation-def VALUE_OF_Point():
return tuple[float, float]
Point = typing.TypeAliasType("Point", VALUE_OF_Point())
annotation-def は アノテーションスコープ を表します。
これはほぼ関数のように動作しますが、細かな違いがいくつかあります。
型エイリアスの値はアノテーションスコープ内で評価されます。
型エイリアスの作成時には評価されず、型エイリアスの __value__ 属性を通じて値にアクセスしたときに初めて評価されます (遅延評価 を参照)。
これにより、型エイリアスはまだ定義されていない名前を参照できます。
名前の後に 型パラメータリスト を追加すると、型エイリアスをジェネリックにできます。 詳しくは ジェネリックな型エイリアス を参照してください。
type は ソフトキーワード です。
Added in version 3.12.
参考
- PEP 695 - 型パラメータの構文
type文と、ジェネリックなクラスおよび関数の構文が導入されました。