4. 実行モデル¶
4.1. プログラムの構造¶
Python プログラムはコードブロックから構成されます。ブロック (block) は、一つのまとまりとして実行される Python プログラムテキストの断片です。モジュール、関数本体、そしてクラス定義はブロックです。また、対話的に入力された個々のコマンドもブロックです。スクリプトファイル (インタプリタに標準入力として与えられたり、インタプリタにコマンドライン引数として与えられたファイル) もコードブロックです。スクリプトコマンド (インタプリタのコマンドライン上で '-c' オプションで指定されたコマンド) もコードブロックです。組み込み関数 eval()
や exec()
に渡された文字列引数もコードブロックです。
コードブロックは、実行フレーム (execution frame) 上で実行されます。実行フレームには、 (デバッグに使われる) 管理情報が収められています。また、現在のコードブロックの実行が完了した際に、どのようにプログラムの実行を継続するかを決定しています。
4.2. 名前づけと束縛 (naming and binding)¶
4.2.1. 名前の束縛¶
名前 (name) は、オブジェクトを参照します。名前を導入するには、名前への束縛 (name binding) 操作を行います。
以下の構造で、名前が束縛されます: 関数の仮引数 (formal parameter) 指定、 import
文、クラスや関数の定義 (定義を行ったブロックで、クラスや関数名を束縛します)、代入が行われるときの代入対象の識別子、 for
ループのヘッダ、 with
文や except
節の as
の後ろ。 "from ... import *
" 形式の import
文は、 import されるモジュール内で定義されている、アンダースコアから始まるもの以外の、全ての名前を束縛します。この形式は、モジュールレベルでしか使えません。
del
文で指定される対象は、(del
の意味付けは、実際は名前の解放 (unbind) ですが) 文の目的上、束縛済みのものとみなされます。
代入文や import 文はいずれも、クラスや関数定義、モジュールレベル (トップレベルのコードブロック) 内で起こります。
ある名前がブロック内で束縛されているなら、 nonlocal
や global
として宣言されていない限り、それはそのブロックのローカル変数 (local variable) です。
ある名前がモジュールレベルで束縛されているなら、その名前はグローバル変数 (global variable) です。
(モジュールコードブロックの変数は、ローカル変数でも、グローバル変数でもあります。)
ある変数があるコードブロック内で使われていて、そのブロックで定義はされていないなら、それは自由変数 (free variable) です。
プログラムテキスト中に名前が出現するたびに、その名前が使われている最も内側の関数ブロック中で作成された 束縛 (binding) を使って名前の参照が行われます。
4.2.2. 名前解決¶
スコープ (scope) は、ブロック内の名前の可視性を決めます。 ローカル変数があるブロック内で定義されている場合、変数のスコープはそのブロックを含みます。 関数ブロック内で名前の定義を行った場合、その中のブロックが名前に別の束縛を行わない限り、定義ブロック内の全てのブロックを含むようにスコープが拡張されます。
ある名前がコードブロック内で使われると、その名前を最も近傍から囲うようなスコープ (最内スコープ: nearest enclosing scope) を使って束縛の解決を行います。こうしたスコープからなる、あるコードブロック内で参照できるスコープ全ての集合は、ブロックの環境(environment)と呼ばれます。
名前が全く見付からなかったときは、 NameError
例外が送出されます。
現在のスコープが関数のもので、名前が使われる場所でローカル変数がまだ値に束縛されていない場合、 UnboundLocalError
例外が送出されます。
UnboundLocalError
は NameError
の子クラスです。
ある名前がコードブロック内のどこかで束縛操作されていたら、そのブロック内で使われるその名前はすべて、現在のブロックへの参照として扱われます。このため、ある名前がそのブロック内で束縛される前に使われるとエラーにつながります。この規則は敏感です。Python には宣言がなく、コードブロックのどこでも名前束縛操作ができます。あるコードブロックにおけるローカル変数は、ブロックのテキスト全体から名前束縛操作を走査することで決定されます。
global
文がブロック内にあると、その文で指定された名前は常にトップレベルの名前空間で束縛された名前を参照します。それらの名前は、トップレベルの名前空間で解決されます。このために、グローバル名前空間、すなわちそのコードブロックを含むモジュールの名前空間と、組み込み名前空間、すなわちモジュール builtins
の名前空間が検索されます。グローバル名前空間が先に検索されます。名前がグローバル名前空間中に見つからなければ、組み込み名前空間が検索されます。 global
文は、その名前が最初に使われる前に記述されていなければなりません。
global
文は、同じブロックの束縛操作と同じスコープを持ちます。ある自由変数の最内スコープに global 文がある場合、その自由変数はグローバル変数とみなされます。
nonlocal
文によって、対応する名前が最内関数スコープでそれ以前に束縛された変数を参照するようになります。もし名前がどの最内関数スコープにも存在しなければ、コンパイル時に SyntaxError
が上げられます。
あるモジュールの名前空間は、そのモジュールが最初に import された時に自動的に作成されます。スクリプトの主モジュール (main module) は常に __main__
と呼ばれます。
クラス定義ブロックと exec()
や eval()
に対する引数は、名前解決の文脈で特別です。クラス定義は、名前を使うことと定義することができる実行可能な文です。これらの参照は、名前解決のための通常のルールに従いますが、束縛されていないローカル変数がグローバルな名前空間から検索されるという例外があります。クラス定義の名前空間はクラスの属性辞書になります。クラス内で定義された名前のスコープは、クラスのブロックに限定されます; メソッドのコードブロックには拡張されません。 – 内包表記やジェネレータ式も関数スコープを利用して実装されているので、スコープの拡張範囲外です。つまり、次のようなコードは失敗します:
class A:
a = 42
b = list(a + i for i in range(10))
4.2.3. 組み込みと制限付きの実行¶
CPython 実装の詳細: ユーザは __builtins__
に触れるべきではありません; これは厳密に実装の詳細です。組み込みの名前空間の中の値をオーバーライドしたいユーザは、 builtins
モジュールを import
して、その属性を適切に変更するべきです。
あるコードブロックの実行に関連する組み込み名前空間は、実際にはコードブロックのグローバル名前空間から名前 __builtins__
を検索することで見つかります; __builtins__
は辞書かモジュールでなければなりません (後者の場合はモジュールの辞書が使われます)。デフォルトでは、 __main__
モジュール中においては、 __builtins__
は組み込みモジュール builtins
です; それ以外の任意のモジュールにおいては、 __builtins__
は builtins
モジュール自身の辞書のエイリアスです。
4.2.4. 動的な機能とのやりとり¶
自由変数の名前解決はコンパイル時でなく実行時に行われます。つまり、以下のコードは42を出力します:
i = 10
def f():
print(i)
i = 42
f()
eval()
と exec()
関数は、名前の解決に、現在の環境の全てを使えるわけではありません。名前は呼び出し側のローカルやグローバル名前空間で解決できます。自由変数は最内名前空間ではなく、グローバル名前空間から解決されます。 [1] exec()
と eval()
関数にはオプションの引数があり、グローバルとローカル名前空間をオーバライドできます。名前空間が一つしか指定されなければ、両方の名前空間として使われます。
4.3. 例外¶
例外とは、コードブロックの通常の制御フローを中断して、エラーやその他の例外的な状況を処理できるようにするための手段です。例外はエラーが検出された時点で 送出 (raise) されます; 例外は、エラーが発生部の周辺のコードブロックか、エラーが発生したコードブロック直接または間接的に呼び出しているコードブロックで 処理 (handle) することができます。
Python インタプリタは、ランタイムエラー (ゼロ除算など) が検出されると例外を送出します。Python プログラムから、 raise
文を使って明示的に例外を送出することもできます。例外ハンドラ (exception handler) は、 try
… except
文で指定することができます。 try
文の finally
節を使うとクリーンアップコード (cleanup code) を指定できます。このコードは例外は処理しませんが、先行するコードブロックで例外が起きても起きなくても実行されます。
Python は、エラー処理に "プログラムの終了 (termination)" モデルを用いています: 例外ハンドラは、プログラムに何が発生したかを把握することができ、ハンドラの外側のレベルに処理を継続することはできますが、(問題のあったコード部分を最初から実行しなおすのでない限り) エラーの原因を修復したり、実行に失敗した操作をやり直すことはできません。
例外が全く処理されないとき、インタプリタはプログラムの実行を終了させるか、対話メインループに処理を戻します。どちらの場合も、例外が SystemExit
でなければ、スタックバックトレース (backtrace) を出力します。
例外は、クラスインスタンスによって識別されます。 except
節はインスタンスのクラスにもとづいて選択されます: これはインスタンスのクラスか、そのベースクラスを参照します。このインスタンスはハンドラによって受け取られ、例外条件に関する追加情報を伝えることができます。
注釈
例外のメッセージは、Python API 仕様には含まれていません。メッセージの内容は、ある Python のバージョンと次のバージョンの間で警告なしに変更される可能性があるので、複数バージョンのインタプリタで動作するようなコードは、例外メッセージの内容に依存させるべきではありません。
try
文については、 try 文 節、 raise
文については raise 文 節も参照してください。
脚注
[1] | この制限は、上記の操作によって実行されるコードが、モジュールをコンパイルしたときには利用できないために起こります。 |