4. 実行モデル

4.1. プログラムの構造

Python プログラムはコードブロックから構成されます。 ブロック (block) は、一つのまとまりとして実行される Python プログラムテキストの断片です。 モジュール、関数本体、そしてクラス定義はブロックであり、対話的に入力された個々のコマンドもブロックです。 スクリプトファイル (インタープリタに標準入力として与えられたり、インタープリタにコマンドライン引数として与えられたファイル) もコードブロックです。 スクリプトコマンド (インタープリタのコマンドライン上で -c オプションで指定されたコマンド) もコードブロックです。 引数 -m を使用して、コマンドラインからトップレベルスクリプト(すなわちモジュール __main__ )として実行されるモジュールもまたコードブロックです。組み込み関数 eval() や exec() に渡された文字列引数もコードブロックです。

コードブロックは、実行フレーム (execution frame) 上で実行されます。実行フレームには、 (デバッグに使われる) 管理情報が収められています。また、現在のコードブロックの実行が完了した際に、どのようにプログラムの実行を継続するかを決定しています。

4.2. 名前づけと束縛 (naming and binding)

4.2.1. 名前の束縛

名前 (name) は、オブジェクトを参照します。名前を導入するには、名前への束縛 (name binding) 操作を行います。

以下の構文が名前を束縛します:

  • 関数の仮引数。

  • クラス定義,

  • 関数定義,

  • 代入式,

  • 代入先 が識別子で、次の代入が行われる箇所にある場合。

    • for ループのヘッダー。

    • with 文、except 節、except* 節の as の後、または構造的パターンマッチングの as パターン内。

    • 構造的パターンマッチングのキャプチャパターン内。

  • import 文.

  • type 文。

  • 型パラメータのリスト。

The import statement of the form from ... import * binds all names defined in the imported module, except those beginning with an underscore. This form may only be used at the module level.

del 文で指定される対象は、(del の意味付けは、実際は名前の解放 (unbind) ですが) 文の目的上、束縛済みのものとみなされます。

代入文や import 文はいずれも、クラスや関数定義、モジュールレベル (トップレベルのコードブロック) 内で起こります。

名前がブロック内で束縛される場合、nonlocal または global で宣言されていなければ、そのブロックのローカル変数です。 名前がモジュールレベルで束縛される場合はグローバル変数です (モジュールのコードブロックの変数は、ローカル変数であると同時にグローバル変数でもあります)。 コードブロック内で使われていても、そこで定義されていない変数は 自由変数 です。

プログラムのテキスト中に現れる各名前は、以下の名前解決規則によって定まる、その名前の 束縛 (binding) を参照します。

4.2.2. 名前解決

スコープ (scope) は、ブロック内の名前の可視性を決めます。 ローカル変数があるブロック内で定義されている場合、変数のスコープはそのブロックを含みます。 関数ブロック内で名前の定義を行った場合、その中のブロックが名前に別の束縛を行わない限り、定義ブロック内の全てのブロックを含むようにスコープが拡張されます。

ある名前がコードブロック内で使われると、その名前を最も近傍から囲うようなスコープ (最内スコープ: nearest enclosing scope) を使って束縛の解決を行います。こうしたスコープからなる、あるコードブロック内で参照できるスコープ全ての集合は、ブロックの環境(environment)と呼ばれます。

名前が全く見付からなかったときは、 NameError 例外が送出されます。 現在のスコープが関数のもので、名前が使われる場所でローカル変数がまだ値に束縛されていない場合、 UnboundLocalError 例外が送出されます。 UnboundLocalError は NameError の子クラスです。

コードブロック内のどこかに名前の束縛操作があると、そのブロック内でのその名前の使用はすべて、現在のブロックへの参照として扱われます。 そのため、束縛する前にその名前をブロック内で使うと、エラーにつながる場合があります。 この規則は分かりにくい点に注意が必要です。 Python では変数の宣言は不要で、コードブロック内のどこでも名前を束縛できます。 ブロックのテキスト全体から名前の束縛操作を探すことで、そのブロックのローカル変数を判断できます。 例は UnboundLocalError についての FAQ 項目 を参照してください。

If the global statement occurs within a block, all uses of the names specified in the statement refer to the bindings of those names in the top-level namespace. Names are resolved in the top-level namespace by searching the global namespace, i.e. the namespace of the module containing the code block, and the builtins namespace, the namespace of the module builtins. The global namespace is searched first. If the names are not found there, the builtins namespace is searched next. If the names are also not found in the builtins namespace, new variables are created in the global namespace. The global statement must precede all uses of the listed names.

global 文は、同じブロックの束縛操作と同じスコープを持ちます。ある自由変数の最内スコープに global 文がある場合、その自由変数はグローバル変数とみなされます。

nonlocal 文は、指定された名前が、最も近い外側の関数スコープで以前に束縛された変数を参照するようにします。 外側のどの関数スコープにもその名前がなければ、コンパイル時に SyntaxError を送出します。 型パラメータ は nonlocal 文で再束縛できません。

あるモジュールの名前空間は、そのモジュールが最初に import された時に自動的に作成されます。スクリプトの主モジュール (main module) は常に __main__ と呼ばれます。

クラス定義のブロックと、exec() や eval() に渡す引数では、名前解決に特別な規則があります。 クラス定義は実行可能な文で、名前を使ったり定義したりできます。 これらの参照は通常の名前解決規則に従いますが、束縛されていないローカル変数をグローバル名前空間で探す点は例外です。 クラス定義の名前空間は、クラスの属性辞書になります。 クラスブロックで定義した名前のスコープはそのブロックに限られ、メソッドのコードブロックには及びません。 内包表記やジェネレータ式も同様ですが、アノテーションスコープ は例外で、外側のクラススコープにアクセスできます。 このため、次のコードは失敗します。

class A:
    a = 42
    b = list(a + i for i in range(10))

一方、次のコードは成功します。

class A:
    type Alias = Nested
    class Nested: pass

print(A.Alias.__value__)  # <type 'A.Nested'>

4.2.3. アノテーションスコープ

Type parameter lists and type statements introduce annotation scopes, which behave mostly like function scopes, but with some exceptions discussed below. Annotations currently do not use annotation scopes, but they are expected to use annotation scopes in Python 3.13 when PEP 649 is implemented.

アノテーションスコープは次の文脈で使われます。

  • ジェネリック型エイリアス の型パラメータのリスト。

  • ジェネリック関数 の型パラメータのリスト。 ジェネリック関数のアノテーションはアノテーションスコープ内で実行されますが、デフォルト値やデコレータはその外で実行されます。

  • ジェネリッククラス の型パラメータのリスト。 ジェネリッククラスの基底クラスとキーワード引数はアノテーションスコープ内で実行されますが、デコレータはその外で実行されます。

  • 型パラメータの上限、制約、デフォルト値 (遅延評価)。

  • 型エイリアスの値 (遅延評価)。

アノテーションスコープは、次の点で関数スコープと異なります。

  • アノテーションスコープは、外側のクラスの名前空間にアクセスできます。 クラススコープの直下、またはクラススコープの直下にある別のアノテーションスコープ内にアノテーションスコープがある場合、その中のコードは、クラス本体で直接実行する場合と同様にクラススコープで定義された名前を使えます。 これは、クラス内で定義された通常の関数が、クラススコープで定義された名前にアクセスできないこととは対照的です。

  • アノテーションスコープ内の式には、yield、yield from、await、:= の式を含められません (アノテーションスコープ内にある別のスコープでは使えます)。

  • アノテーションスコープで定義された名前は、内側のスコープの nonlocal 文では再束縛できません。 アノテーションスコープ内に現れ得る構文要素のうち、新しい名前を導入できるのは型パラメータだけなので、この制限の対象も型パラメータだけです。

  • アノテーションスコープには内部的な名前がありますが、その名前はスコープ内で定義したオブジェクトの 修飾名 には反映されません。 オブジェクトの __qualname__ は、その外側のスコープで定義した場合と同じになります。

Added in version 3.12: PEP 695 の一部として、Python 3.12 でアノテーションスコープを導入しました。

バージョン 3.13 で変更: PEP 696 で導入された型パラメータのデフォルト値にも、アノテーションスコープを使うようになりました。

4.2.4. 遅延評価

The values of type aliases created through the type statement are lazily evaluated. The same applies to the bounds, constraints, and default values of type variables created through the type parameter syntax. This means that they are not evaluated when the type alias or type variable is created. Instead, they are only evaluated when doing so is necessary to resolve an attribute access.

例:

>>> type Alias = 1/0
>>> Alias.__value__
Traceback (most recent call last):
  ...
ZeroDivisionError: division by zero
>>> def func[T: 1/0](): pass
>>> T = func.__type_params__[0]
>>> T.__bound__
Traceback (most recent call last):
  ...
ZeroDivisionError: division by zero

この例では、型エイリアスの __value__ 属性または型変数の __bound__ 属性にアクセスした時点で初めて例外を送出します。

この動作は主に、型エイリアスや型変数の作成時点ではまだ定義されていない型を参照する場合に役立ちます。 例えば、遅延評価によって相互に再帰する型エイリアスを作成できます。

from typing import Literal

type SimpleExpr = int | Parenthesized
type Parenthesized = tuple[Literal["("], Expr, Literal[")"]]
type Expr = SimpleExpr | tuple[SimpleExpr, Literal["+", "-"], Expr]

遅延評価される値は アノテーションスコープ 内で評価されます。 そのため、その値の中に現れる名前は、直近の外側のスコープで使われた場合と同じように検索されます。

Added in version 3.12.

4.2.5. 組み込みと制限付きの実行

ユーザは __builtins__ に触れるべきではありません; これは厳密に実装の詳細です。組み込みの名前空間の中の値をオーバーライドしたいユーザは、 builtins モジュールを import して、その属性を適切に変更するべきです。

あるコードブロックの実行に関連する組み込み名前空間は、実際にはコードブロックのグローバル名前空間から名前 __builtins__ を検索することで見つかります; __builtins__ は辞書かモジュールでなければなりません (後者の場合はモジュールの辞書が使われます)。デフォルトでは、 __main__ モジュール中においては、 __builtins__ は組み込みモジュール builtins です; それ以外の任意のモジュールにおいては、 __builtins__ は builtins モジュール自身の辞書のエイリアスです。

4.2.6. 動的な機能とのやりとり

自由変数の名前解決はコンパイル時でなく実行時に行われます。つまり、以下のコードは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 でなければ、スタックのトレースバックを出力します。

例外は、クラスインスタンスによって識別されます。 except 節はインスタンスのクラスにもとづいて選択されます: これはインスタンスのクラスか、その 非仮想基底クラス を参照します。このインスタンスはハンドラによって受け取られ、例外条件に関する追加情報を伝えることができます。

注釈

例外のメッセージは、Python API 仕様には含まれていません。メッセージの内容は、ある Python のバージョンと次のバージョンの間で警告なしに変更される可能性があるので、複数バージョンのインタプリタで動作するようなコードは、例外メッセージの内容に依存させるべきではありません。

try 文については、 try 文 節、 raise 文については raise 文 節も参照してください。

4.4. Runtime Components

4.4.1. General Computing Model

Python's execution model does not operate in a vacuum. It runs on a host machine and through that host's runtime environment, including its operating system (OS), if there is one. When a program runs, the conceptual layers of how it runs on the host look something like this:

host machine
process (global resources)
thread (runs machine code)

Each process represents a program running on the host. Think of each process itself as the data part of its program. Think of the process' threads as the execution part of the program. This distinction will be important to understand the conceptual Python runtime.

The process, as the data part, is the execution context in which the program runs. It mostly consists of the set of resources assigned to the program by the host, including memory, signals, file handles, sockets, and environment variables.

Processes are isolated and independent from one another. (The same is true for hosts.) The host manages the process' access to its assigned resources, in addition to coordinating between processes.

Each thread represents the actual execution of the program's machine code, running relative to the resources assigned to the program's process. It's strictly up to the host how and when that execution takes place.

From the point of view of Python, a program always starts with exactly one thread. However, the program may grow to run in multiple simultaneous threads. Not all hosts support multiple threads per process, but most do. Unlike processes, threads in a process are not isolated and independent from one another. Specifically, all threads in a process share all of the process' resources.

The fundamental point of threads is that each one does run independently, at the same time as the others. That may be only conceptually at the same time ("concurrently") or physically ("in parallel"). Either way, the threads effectively run at a non-synchronized rate.

注釈

That non-synchronized rate means none of the process' memory is guaranteed to stay consistent for the code running in any given thread. Thus multi-threaded programs must take care to coordinate access to intentionally shared resources. Likewise, they must take care to be absolutely diligent about not accessing any other resources in multiple threads; otherwise two threads running at the same time might accidentally interfere with each other's use of some shared data. All this is true for both Python programs and the Python runtime.

The cost of this broad, unstructured requirement is the tradeoff for the kind of raw concurrency that threads provide. The alternative to the required discipline generally means dealing with non-deterministic bugs and data corruption.

4.4.2. Python Runtime Model

The same conceptual layers apply to each Python program, with some extra data layers specific to Python:

host machine
process (global resources)
Python global runtime (state)
Python interpreter (state)
thread (runs Python bytecode and "C-API")
Python thread state

At the conceptual level: when a Python program starts, it looks exactly like that diagram, with one of each. The runtime may grow to include multiple interpreters, and each interpreter may grow to include multiple thread states.

注釈

A Python implementation won't necessarily implement the runtime layers distinctly or even concretely. The only exception is places where distinct layers are directly specified or exposed to users, like through the threading module.

注釈

The initial interpreter is typically called the "main" interpreter. Some Python implementations, like CPython, assign special roles to the main interpreter.

Likewise, the host thread where the runtime was initialized is known as the "main" thread. It may be different from the process' initial thread, though they are often the same. In some cases "main thread" may be even more specific and refer to the initial thread state. A Python runtime might assign specific responsibilities to the main thread, such as handling signals.

As a whole, the Python runtime consists of the global runtime state, interpreters, and thread states. The runtime ensures all that state stays consistent over its lifetime, particularly when used with multiple host threads.

The global runtime, at the conceptual level, is just a set of interpreters. While those interpreters are otherwise isolated and independent from one another, they may share some data or other resources. The runtime is responsible for managing these global resources safely. The actual nature and management of these resources is implementation-specific. Ultimately, the external utility of the global runtime is limited to managing interpreters.

In contrast, an "interpreter" is conceptually what we would normally think of as the (full-featured) "Python runtime". When machine code executing in a host thread interacts with the Python runtime, it calls into Python in the context of a specific interpreter.

注釈

The term "interpreter" here is not the same as the "bytecode interpreter", which is what regularly runs in threads, executing compiled Python code.

In an ideal world, "Python runtime" would refer to what we currently call "interpreter". However, it's been called "interpreter" at least since introduced in 1997 (CPython:a027efa5b).

Each interpreter completely encapsulates all of the non-process-global, non-thread-specific state needed for the Python runtime to work. Notably, the interpreter's state persists between uses. It includes fundamental data like sys.modules. The runtime ensures multiple threads using the same interpreter will safely share it between them.

A Python implementation may support using multiple interpreters at the same time in the same process. They are independent and isolated from one another. For example, each interpreter has its own sys.modules.

For thread-specific runtime state, each interpreter has a set of thread states, which it manages, in the same way the global runtime contains a set of interpreters. It can have thread states for as many host threads as it needs. It may even have multiple thread states for the same host thread, though that isn't as common.

Each thread state, conceptually, has all the thread-specific runtime data an interpreter needs to operate in one host thread. The thread state includes the current raised exception and the thread's Python call stack. It may include other thread-specific resources.

注釈

The term "Python thread" can sometimes refer to a thread state, but normally it means a thread created using the threading module.

Each thread state, over its lifetime, is always tied to exactly one interpreter and exactly one host thread. It will only ever be used in that thread and with that interpreter.

Multiple thread states may be tied to the same host thread, whether for different interpreters or even the same interpreter. However, for any given host thread, only one of the thread states tied to it can be used by the thread at a time.

Thread states are isolated and independent from one another and don't share any data, except for possibly sharing an interpreter and objects or other resources belonging to that interpreter.

Once a program is running, new Python threads can be created using the threading module (on platforms and Python implementations that support threads). Additional processes can be created using the os, subprocess, and multiprocessing modules. Coroutines (async) can be run using asyncio in each interpreter, typically only in a single thread (often the main thread).

脚注