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