Tag: internals
-
31. 関数呼び出し
#31. 関数呼び出し 関数呼び出しは、CPython の最も重要な実行パスの 1 つです。呼び出しは、バイトコードの実行、フレーム、引数バインディング、記述子、メソッド、クロージャ、C API、参照カウント、例外、戻り処理などの複数のシステムを同時に接続します。 簡単な呼び出し: python id="wauh11" result = f(1, 2) ソースレベルでは小さく見えます。実行時、CPython は次のことを行う必要があります。```text id="rhdr0d" load the callable load the arguments choose the correct call protocol bind arguments to parameters create or initialize a frame if calling Python code execute the callee return a result or propagate an exception store the result ## 31.1 通話の意味 Python では、呼び出し式は次の一般的な形式になります。 ``` python id = "a7ltua" callable_object ( arguments ) ``` 括弧の前のオブジェクトは呼び出し可能である必要があります。…
-
35. 発電機
#35. 発電機 ジェネレーターは再開可能な関数です。通常の関数は、開始、実行、および 1 つの戻り値で終了します。ジェネレーターは、開始して値を生成し、フレームを一時停止し、後で同じ命令位置から再開して別の値を生成し、終了するまで繰り返すことができます。 ジェネレーター関数は、以下を含む関数本体です。 yield 。 python id="j7t4va" def numbers(): yield 1 yield 2 yield 3 この関数を呼び出しても、本体はすぐには実行されません。 python id="oyb9ik" g = numbers() この呼び出しによりジェネレーター オブジェクトが作成されます。ジェネレーターが再開されると本体が開始されます。 python id="9sgmxp" print(next(g)) print(next(g)) print(next(g)) 出力: text id="wj3i3f" 1 2 3 最後の値の後、次の再開で値が発生します StopIteration 。 35.1 ジェネレータ関数とジェネレータ オブジェクト ジェネレーター関数は、次のように定義された呼び出し可能関数です。 def 。 ジェネレーター オブジェクトは、ジェネレーター関数が呼び出されたときに返される再開可能なイテレーターです。```python id="nckwxg" def gen(): yield 1 print(gen) print(gen()) 概念的には: text id="hfh6hz" gen function object gen() generator object suspended execution state code object frame…
-
14. 文字列、バイト、Unicode
#14. 文字列、バイト、Unicode テキスト データとバイナリ データは、Python では別個のオブジェクト ファミリです。 str Unicode テキストを表します。 bytes 不変のバイナリデータを表します。 bytearray 可変バイナリデータを表します。 This separation is one of Python 3’s most important runtime design choices.テキストには文字とエンコーディングがあります。 Binary data has bytes. CPython implements these concepts with different object layouts, APIs, and invariants. 14.1 テキスト データとバイナリ データ A string is text: python id="ly45du" s = "hello" バイト オブジェクトはバイナリ データです。 python id="1wh8hi" b = b"hello" ASCII コンテンツでは似ているように見えますが、タイプは異なります。 python id="iqtxra" print(type("hello")) # <class 'str'>…
-
10. ガベージコレクター
#10. ガベージコレクター CPython は、メインのメモリ管理メカニズムとして参照カウントを使用します。参照カウントでは、ほとんどのオブジェクトは、最後の強い参照が消えるとすぐに破棄されます。 参照カウントには大きな制限が 1 つあります。それは、参照サイクルを単独で再利用できないことです。 ガベージ コレクターは、コンテナ オブジェクトの到達不能なサイクルを見つけて再利用するために存在します。これは参照カウントを補足するものであり、それに代わるものではありません。 10.1 参照カウントにヘルプが必要な理由 参照カウントがゼロになるのは、オブジェクトを指す強参照がない場合のみです。 これは通常のオブジェクト グラフで機能します。```python x = [] del x サイクルでは機能しません。 ``` python a = [] b = [] a . append ( b ) b . append ( a ) del a del b ``` 2 つの名前が削除された後も、リストは引き続き相互参照します。 ``` text list A ---> list B list B ---> list A ``` それらの参照カウントはゼロ以外のままです。しかし、ライブ Python コードはそれらに到達できません。 参照カウントではローカル所有権が確認されます。ガベージ コレクションでは到達可能性が確認されます。 ## 10.2 ガベージコレクターが追跡するもの CPython…
-
12. オブジェクトのレイアウトとタイプ スロット
12. オブジェクトのレイアウトとタイプ スロット CPython は、すべてのランタイム値をオブジェクトとして表します。各オブジェクトにはメモリ レイアウトがあり、各オブジェクトのタイプはそのメモリがどのように解釈されるべきかを記述します。 オブジェクトのレイアウトは次のように答えます。 text What fields exist inside this object? Where are the references to other Python objects? How large is one instance? Does the object have variable-sized trailing storage? Does the object participate in cyclic garbage collection? タイプ スロットの答えは次のとおりです。```text How is this object called? How is it deallocated? How does attribute lookup work? How does indexing work? How does addition work? How does iteration work?…
-
25. バイトコードの生成
#25. バイトコードの生成 バイトコード生成は、CPython が構造化構文を実行可能な仮想マシン命令に変換する段階です。 パーサーは AST を構築します。 シンボル テーブルはスコープの動作を決定します。 次に、コンパイラは、Python セマンティクスを実装するバイトコード命令を発行します。 このソースの場合: python id="bjlwm8" def add(a, b): return a + b CPython は次のようなバイトコードを生成します。 text id="plhxq4" LOAD_FAST a LOAD_FAST b BINARY_OP + RETURN_VALUE 正確な命令名と形式は Python のバージョンによって異なりますが、モデルは安定しています。```text id="ecx81v" bytecode is a low-level instruction stream executed by the CPython virtual machine バイトコードの生成は、 AST の構築とスコープ分析の後に行われます。 ``` text id = "5v2o9v" source ↓ tokenization ↓ parsing ↓ AST ↓ symbol table ↓ bytecode generation ↓…
-
15. リスト、タプル、配列
#15. リスト、タプル、配列 リスト、タプル、および配列のようなオブジェクトは、順序付けられたコレクションを表します。これらはすべてインデックス付きアクセスをサポートしていますが、ストレージ モデル、可変性ルール、パフォーマンスのトレードオフが異なります。 リストは、オブジェクト参照の変更可能なシーケンスです。 タプルは、オブジェクト参照の不変のシーケンスです。 配列のようなオブジェクトは、コンパクトな型付きデータを格納するか、連続したバッファを公開します。 CPython コンテナーは、その型が RAW ストレージ用に特別に設計されていない限り、参照を格納するため、これらの区別は重要です。 15.1 順序付けられたコレクション Python にはいくつかの順序付きコレクション型があります。 タイプ 可変 店舗 主な用途 list はい オブジェクト参照 一般的な可変シーケンス tuple いいえ オブジェクト参照 固定レコード、不変グループ array.array はい 生の型付き値 コンパクトな数値ストレージ bytes いいえ 生のバイト 不変バイナリデータ bytearray はい 生のバイト 変更可能なバイナリ データ memoryview ビューに依存 生のバッファビュー ゼロコピーバッファアクセス リストとタプルには、あらゆるタイプのオブジェクトを格納できます。 python xs = [1, "two", object()] t = (1, "two", object()) 配列には、1 つのマシンレベルの型の値が格納されます。```python from array import array nums = array("i", [1, 2, 3]) CPython リストには、…
-
29. スタックベースの実行
#29. スタックベースの実行 CPython は、ほとんどのバイトコードをスタック マシンで実行します。スタック マシンは、すべての命令でソース レジスタとデスティネーション レジスタを明示的に指定するのではなく、暗黙的なオペランド スタックを使用します。 CPython では、このスタックは現在のフレームに属します。 Python オブジェクトへの参照を保存します。バイトコード命令は、オブジェクトのプッシュ、オブジェクトのポップ、オブジェクトの検査、オブジェクトの置換、およびオブジェクトを使用した新しい結果の計算を行います。 簡単な表現: python id="kz6m7x" x = a + b 概念的には次のように実行されます。 text id="eurdpx" LOAD_FAST a push a LOAD_FAST b push b BINARY_OP + pop b and a, push result STORE_FAST x pop result into local x 命令ストリームには次のような記述はありません。 text id="ardj57" add local_a, local_b, local_x 代わりに、次のように書かれています。```text id="jzzlmf" load a load b add top two stack values store result ## 29.1 CPython…
-
22. コンパイラパス
#22. コンパイラパス コンパイラ パスは、AST およびシンボル テーブル情報を実行可能コード オブジェクトに変換します。 初期段階では構造的な質問に答えます。```text id="lfk0j9" tokenizer: What lexical units are in the source? parser: What syntax tree do these tokens form? symbol table: What scope does each name belong to? コンパイラーは実行に関する質問に答えます。 text id="ju2gsy" Which bytecode instructions should be emitted? Which constants belong in co_consts? Which names belong in co_names? Which local variables belong in co_varnames? Where should jumps go? How large can the evaluation stack grow?…
-
42. インポートロック
#42. インポートロック インポート ロックは、安全でない同時インポートを防止する同期機構です。 CPython では、インポートは名前の検索だけではありません。モジュールオブジェクトを作成したり、突然変異したりする可能性があります。 sys.modules 、任意の Python コードの実行、拡張モジュールの初期化、パッケージ属性の更新、ソース ファイルのコンパイル、バイトコード キャッシュの読み取り、パッケージ初期化コードの実行を行います。 ロックを行わないと、2 つのスレッドが同じモジュールを同時にインポートし、一貫性のないモジュール状態が観察される可能性があります。 インポートは実行であり、実行により共有ランタイム状態が変化するため、インポート ロックが存在します。 42.1 インポートにロックが必要な理由 このモジュールについて考えてみましょう。```python id="ez8v8a" cache.py print("initializing cache") items = {} def get(key): return items[key] ここで、これを同時に実行する 2 つのスレッドを考えてみましょう。 python id="2pklaf" import cache 同期がないと、両方のスレッドが次のような可能性があります。 text id="oy5qmp" create a module object insert or overwrite sys.modules["cache"] execute cache.py initialize items twice observe a partially initialized module bind different module objects ## 42.2 インポートによりグローバル ランタイム状態が変更される インポートは共有状態にタッチします。 重要な共有構造には次のものがあります。 ```text id="yxk2bl"…
-
38. 内包表記
#38. 内包表記 内包表記は、別の反復可能オブジェクトからコンテナーまたはジェネレーターのような反復子を構築するためのコンパクトな構文です。 CPython は、それらを独自の実行スコープを持つコンパイル済みコード オブジェクトとして実装します。 一般的な形式: python [x * 2 for x in xs] {x * 2 for x in xs} {x: x * 2 for x in xs} (x * 2 for x in xs) これらは以下に対応します。```text list comprehension set comprehension dict comprehension generator expression ## 38.1 リストの内包表記 リスト内包では、熱心にリストを構築します。 ``` python ys = [ x * 2 for x in xs ] ``` 概念的には : ``` python ys =…
-
1. CPython とは
#1. CPython とは CPython は、Python プログラミング言語の主要な実装です。これは、Python を python.org、パッケージ マネージャー、Linux ディストリビューション、Homebrew、pyenv、Docker イメージ、またはほとんどのクラウド ランタイムからインストールするときにほとんどの人が使用する実装です。 CPython には 2 つの役割があります。 まず、Python 言語を実装します。これは、Python ソース コードがどのように解析、コンパイル、実行され、標準ライブラリに接続されるかを定義します。 2 番目に、Python エコシステムの実用的な参照ポイントとして機能します。他の実装は言語仕様に従う場合がありますが、CPython は、ほとんどのパッケージ、ツール、デバッガー、プロファイラー、および C 拡張機能がテストされる実装です。 CPython ソース ツリーには、インタープリター、コンパイラー、オブジェクト システム、ランタイム、C API、標準ライブラリ、テスト スイート、ドキュメント、およびビルド機構が含まれています。公式開発者ガイドでは、CPython を、ソース ツリーで維持される内部ドキュメントを持つ変化するコード ベースとして説明しています。 ([Python 開発者ガイド][1]) 1.1 言語としての Python と実装としての CPython 言語はPythonです。 CPython はその言語の実装の 1 つです。 Python 言語では、構文、名前、式、ステートメント、オブジェクト、モジュール、例外、反復、非同期動作、インポートなどの目に見える動作が記述されるため、この区別は重要です。 CPython では、その動作を実際のマシンで実行する具体的な方法の 1 つについて説明します。 次のような Python プログラム:```python def add(a, b): return a + b print(add(2, 3)) ```言語レベルの Python です。言語は私たちにそれを伝えます def 関数オブジェクトを作成します。…
-
43. 記述子
#43. 記述子 記述子は、別のオブジェクトの属性アクセスを制御するオブジェクトです。記述子は、Python のオブジェクト モデルの背後にある主要なメカニズムの 1 つです。メソッドがインスタンスにどのようにバインドされるかについて説明します。 property 動作、方法 staticmethod そして classmethod 動作、スロットの動作、および Python レベルの構文に接続する CPython レベルの型操作の数。 言語レベルでは、記述子は次のメソッドの 1 つ以上を定義するオブジェクトです。 python id="x7hcrg" __get__(self, obj, objtype=None) __set__(self, obj, value) __delete__(self, obj) オブジェクト __get__ 記述子です。 オブジェクト __set__ または __delete__ データ記述子です。 非データ記述子とデータ記述子の区別により、検索の優先順位が制御されます。 43.1 記述子が存在する理由 Python の属性アクセスは簡単に見えます。 python id="96l8i5" obj.name ただし、この式は「という名前のフィールドを読み取る」という意味ではありません。 name 記憶から。」 それは次のことを意味します:```text id="drqc0j" ask the object's type how attribute lookup works search descriptors and dictionaries in a defined order possibly call descriptor…
-
23. コードオブジェクト
#23. コードオブジェクト コード オブジェクトは、実行可能な Python コードを CPython がコンパイルして表現したものです。 バイトコードとメタデータが含まれています。インタプリタはそれを実行できますが、コード オブジェクト自体は、グローバル、デフォルト引数、クロージャ セル、バインドされたメソッドなどの実行時状態を保持しません。 このソースの場合: python def add(a, b): return a + b 関数オブジェクト add コードオブジェクトが含まれています:```python code = add. code print(code.co_name) print(code.co_varnames) print(code.co_consts) print(code.co_names) ## 23.1 コンパイルパイプラインでの位置 コード オブジェクトはコンパイルの出力です。 ``` text source text ↓ tokenization ↓ parsing ↓ AST ↓ symbol table ↓ compiler ↓ code object ↓ frame execution ``` コード オブジェクトは、コンパイラとインタプリタ間の受け渡しです。 コンパイラはコード オブジェクトを生成します。 評価ループはフレーム内のコード オブジェクトを実行します。 ## 23.2 コードオブジェクトと関数オブジェクト 関数オブジェクトはコード オブジェクトをラップします。 例:…
-
36. コルーチンと非同期
#36. コルーチンと非同期 コルーチンは、非同期プログラミングに使用される再開可能な計算です。 Python コードを一時停止させます。 await ポイントに戻り、制御をイベント ループに戻し、後で待機中の操作の結果が得られたときに再開します。 コルーチンはジェネレーターと似ており、どちらも一時停止後も実行状態を保持します。違いはプロトコルと目的です。 ジェネレーターはイテレーター・コンシューマーに値を生成します。 コルーチンは他の非同期操作を待機し、最終的に 1 つの最終結果を返します。 python id="o2u8bi" async def fetch(): data = await read() return data 電話をかける fetch() 本体を最後まで実行しません。コルーチンオブジェクトを作成します。```python id="9i5ai1" coro = fetch() ## 36.1 コルーチン関数とコルーチン オブジェクト アン ` async def ` ステートメントはコルーチン関数を作成します。 コルーチン関数を呼び出すと、コルーチン オブジェクトが作成されます。 ``` python id = "rt8ky9" async def work (): return 42 coro = work () ``` 概念的には : ``` text id = "q71j65" work coroutine function object…
-
21. シンボルテーブル
#21. シンボルテーブル 解析によって AST が生成された後、CPython はスコープ分析を実行します。 この段階ではシンボル テーブルを構築します。 シンボル テーブルには、各スコープ内で名前がどのように動作するかが記録されます。これにより、名前がローカル、グローバル、フリー、セル、パラメータ、インポート、注釈付き、またはネストされたスコープから参照されるかどうかが決まります。 このソースの場合:```python x = 10 def outer(): y = 20 def inner(): return x + y return inner シンボル テーブル フェーズによって次のことが決まります。```text x global from inner y free variable in inner y cell variable in outer inner local variable in outer outer global variable in module ```バイトコード生成はそれに依存するため、この分析は不可欠です。ローカル変数のロードには、グローバル変数またはクロージャ変数のロードとは異なるバイトコードが使用されます。 ## 21.1 コンパイルパイプラインでの位置 シンボル テーブル フェーズは、AST 構築とバイトコード生成の間にあります。```text source ↓ tokenization ↓ parsing ↓ AST ↓…
-
41. パッケージ
#41. パッケージ パッケージは、他のモジュールを含めることができるモジュールです。 CPython では、パッケージは独立したオブジェクト カテゴリではありません。これはまだモジュール オブジェクトですが、インポート システムにサブモジュールを探す場所を指示するインポート メタデータがあります。 Python レベルでは、このディレクトリをパッケージにすることができます。 text app/ __init__.py config.py server.py 次のようにインポートできます。 python import app import app.config from app.server import run 重要なルールはシンプルです。```text A package is a module with submodule search locations. ## 41.1 パッケージはモジュールです パッケージオブジェクトにはタイプがあります ` module ` 。 ``` python import email print ( type ( email )) print ( email . __name__ ) ``` 出力: ``` text < class 'module' > email ```…
-
9. 参照カウント
#9. 参照カウント 参照カウントは、CPython の主要なメモリ管理メカニズムです。すべての通常のオブジェクトには、現在そのオブジェクトを指している強参照の数が含まれています。このカウントがゼロになると、CPython はオブジェクトを即座に破棄できます。 この設計は、CPython と他の多くの言語ランタイムの最も明確な違いの 1 つです。 CPython には循環ガベージ コレクターがありますが、コレクターは参照カウントを補います。ほとんどのオブジェクトは、定期的なトレースではなく、参照カウントの遷移によって再利用されます。 9.1 核となるアイデア Python オブジェクトは、何かがそのオブジェクトへの参照を所有している間は生き続けます。 概念的には:```text object created reference count = 1 another owner stores the object reference count += 1 an owner releases the object reference count -= 1 reference count reaches 0 object is deallocated 例: python x = [] y = x del x del y ```リスト オブジェクトが作成され、バインドされます。 x 。バインディング y = x 同じリストへの別の参照を作成します。削除中 x 参照を…
-
28. フレーム
#28. フレーム フレームは、Python コードの 1 回のアクティブな実行の実行時レコードです。 CPython は、Python 関数の呼び出し、モジュール本体の実行、クラス本体の実行、ジェネレーターの再開、またはコルーチンの再開を行うときに、フレームのような実行レコードを使用して現在の状態を保持します。 コード オブジェクトは、何を実行するかを示します。 フレームには、現在どこで実行されているか、および現在どのような値が生きているかが示されます。 text code object = immutable instructions and metadata frame = mutable execution state for one run of that code この関数の場合:```python def add(a, b): c = a + b return c のために作られたフレーム ` add ( 2 , 3 ) ` 現在の引数値、ローカル変数スロット、スタック値、命令位置、例外状態、および実行コンテキストへのリンクが含まれます。 ## 28.1 フレームが存在する理由 Python プログラムでは、同時に多数のアクティブな呼び出しを行うことができます。 ``` python def a (): return b () def b (): return c…
-
3. リポジトリのレイアウト
#3. リポジトリのレイアウト CPython リポジトリは、インタプリタの主要なサブシステム (オブジェクト実装、ランタイム機構、コンパイラ パイプライン、パーサー、組み込みモジュール、標準ライブラリ、テスト、ドキュメント、プラットフォーム ビルド ファイル) を中心に編成されています。 適切な最初のパスは、ソース ツリーを責任のマップとして扱うことです。```text cpython/ Include/ Objects/ Python/ Parser/ Modules/ Lib/ Programs/ Tools/ Doc/ Grammar/ PC/ PCbuild/ Mac/ ## 3.1 最上位構造 |ディレクトリ |主な役割 | | ----------- | --------------------------------------------------- | |`Include/`|パブリック、内部、プライベート C ヘッダー | |`Objects/`|コア オブジェクト タイプの実装 | |`Python/`|ランタイム、コンパイラ、インタープリタ ループ、初期化 | |`Parser/`|トークナイザーとパーサーのサポート コード | |`Grammar/`|文法入力ファイル | |`Modules/`| C で書かれた組み込みモジュールと拡張モジュール |`Lib/`| Python標準ライブラリ | |`Lib/test/`| CPython 回帰テスト スイート | |`Programs/`|実行可能エントリ ポイント | |`Tools/`|開発者および構築ツール | |`Doc/`|ドキュメントのソース |…
-
8. PyObject と PyVarObject
#8。 PyObject そして PyVarObject PyObject そして PyVarObject は、CPython オブジェクトの背後にある基本レイアウトです。これらは Python クラスではありません。これらは、ランタイムが共通のポインター型を通じて多くの異なるオブジェクト実装を処理できるようにする C レベルの構造体規則です。 実行時、CPython のほとんどのオブジェクト参照は次のように表されます。```c PyObject * ## 8.1 共通オブジェクトヘッダー 簡略化された ` PyObject ` 次のようになります : ``` c typedef struct { Py_ssize_t ob_refcnt ; PyTypeObject * ob_type ; } PyObject ; ``` 実際の定義では、特にデバッグ ビルド、トレース ビルド、および最新の CPython バージョンで、マクロとビルド依存フィールドが使用されます。しかし、本質的なアイデアは安定しています。 ``` text PyObject reference count type pointer ``` 参照カウントは所有権を追跡します。 型ポインタは、オブジェクトがどのように動作するかを CPython に伝えます。 通常の CPython オブジェクトはすべて、この共通ヘッダーで始まります。そのため、ランタイムは ` PyObject *` コンパイル時に完全な具体的な構造体を知らなくても、その型を検査できます。 ## 8.2 すべてのオブジェクトが同じように始まる理由 次の…
-
18. トークン化
#18. トークン化 トークン化は、CPython のコンパイル パイプラインの最初の構造段階です。 Python ソース テキストを受け取り、トークンのストリームを生成します。パーサーはそのトークン ストリームを消費し、そこから構文構造を構築します。 この段階では、CPython はプログラムが意味があるかどうかをまだ知りません。名前、数値、文字列、演算子、改行、インデント、ファイルの終わりマーカーなどの語彙単位のみを認識します。 トークナイザーは次のように変換します。 python def add(a, b): return a + b 次のような形のストリームになります。 text NAME "def" NAME "add" LPAR "(" NAME "a" COMMA "," NAME "b" RPAR ")" COLON ":" NEWLINE "\n" INDENT " " NAME "return" NAME "a" PLUS "+" NAME "b" NEWLINE "\n" DEDENT "" ENDMARKER "" 正確なトークン名とパーサー インターフェイスは CPython のバージョンによって異なりますが、中心的な考え方は安定しています。 Python 標準ライブラリは、次の方法で Python レベルのトークナイザーを公開します。 tokenize 一方、CPython のパーサーは内部で独自の C トークナイザーを使用します。一般の人々…
-
33. 属性の検索
#33. 属性の検索 属性検索は、次のような式を評価するために使用されるランタイム プロセスです。```python id="5ob0m9" obj.name 単純な属性式が大量の機械をトリガーする可能性があります。 ``` text id = "b2zmcv" find the object 's type search the type and its base classes handle descriptors check the instance dictionary call custom attribute hooks return a value or raise AttributeError ```属性の検索は動的です。結果は、ランタイム オブジェクト、そのクラス、その基本クラス、そのインスタンス ディクショナリ、記述子、メタクラス、およびユーザー定義のフックによって異なります。 ## 33.1 基本的な属性アクセス 式:```python id="67bubm" obj.x ```CPython に、という名前の属性を検索するよう依頼します。`"x"`の上`obj`。 見つかった場合、ルックアップは Python オブジェクトを返します。 欠落している場合は値が上がります`AttributeError`。 例:```python id="l53g0p" class C: pass obj = C() obj.x = 10 print(obj.x) ```割り当てストア`x`インスタンス辞書内:```text id="kz7fxs" obj.__dict__["x"]…
-
16. 辞書とセット
#16. 辞書とセット ディクショナリとセットは、CPython の主要なハッシュ テーブル コンテナです。辞書はキーを値にマッピングします。セットには、値が関連付けられていないキーが格納されます。 これらは Python のあらゆる場所で使用されます。```text id="cp7dx7" module globals class namespaces instance attributes keyword arguments function annotations import caches memoization tables membership indexes deduplication sets ## 16.1 辞書の意味論 辞書はハッシュ可能なキーを値にマッピングします 。``` python id = "cvrlq9" d = { "name" : "Ada" , "age" : 36 , } print ( d [ "name" ]) # Ada ``` キーはハッシュ可能である必要があります 。 値には任意のオブジェクトを指定できます 。``` python id = "mb4tqx" d = {} d…
-
1. オリエンテーション
章 タイトル 1 CPython とは 2 ソースから CPython を構築する 3 リポジトリのレイアウト 4 CPython C コードを読む 5 ランタイムモデル 6 ソースコードから実行まで
-
20. AST
#20. AST 抽象構文ツリーは通常 AST と呼ばれ、解析後の Python ソース コードの構造化表現です。 トークナイザーは、トークンのフラット ストリームを生成します。パーサーは文法を認識します。 AST は、結果をステートメントと式のツリーとして記録します。 このソースの場合: python x = 1 + 2 AST は次のような形になります。```text Module Assign targets: Name id="x", ctx=Store value: BinOp left: Constant value=1 op: Add right: Constant value=2 ## 20.1 コンパイルパイプラインでの位置 AST は解析とコンパイラ分析の間に位置します。 ``` text source bytes ↓ tokenization ↓ parsing ↓ AST ↓ AST validation ↓ symbol table ↓ compiler ↓ code object ↓ bytecode execution ``` パーサーは AST を構築します。後のフェーズではそれを消費します。…
-
34. 例外処理
#34. 例外処理 例外処理は、操作が正常に完了できない場合に CPython が使用する制御フロー システムです。露骨な内容もカバーします raise ステートメント、失敗した操作、失敗したインポート、失敗した呼び出し、ジェネレーターの終了、コンテキスト マネージャーのクリーンアップ、トレースバックの構築、およびフレームを介した伝播。 ソースレベルでは、例外は次のようになります。 python id="cq34p8" try: value = risky() except ValueError: value = 0 実行時、CPython は次のことを行う必要があります。```text id="o1a48o" execute the protected bytecode range detect failure record the active exception find a matching handler restore the frame stack to a valid state jump to handler bytecode run cleanup code propagate if no handler matches ## 34.1 例外とは何か 例外は、異常な制御フローを表すオブジェクトです。 ほとんどの例外は、から派生したクラスのインスタンスです。 ` BaseException ` 。 ``` python…
-
5. ランタイムモデル
#5. ランタイムモデル CPython ランタイムは、プロセスの開始後、Python コードの実行が終了するまでに存在する機構です。インタプリタ状態、スレッド状態、モジュール、ビルトイン、メモリ アロケータ、例外状態、インポート状態、フレーム、保留中の呼び出し、シグナル処理、およびシャットダウン動作を所有します。 Python プログラムは一連のステートメントとして実行されるように見えます。 CPython は、階層化されたランタイム システム内でそれを実行します。```text operating system process CPython runtime interpreter state thread state frame stack executing code object bytecode instructions object operations ## 5.1 プロセス、ランタイム、インタプリタ、スレッド、フレーム 実行中の CPython プログラムには、複数のネストされた実行ユニットがあります。 | 単位 | 意味 | | ---------- -- | -------------------------------------------------------------------- | | プロセス | CPython 実行可能ファイルまたは埋め込みランタイムを含む OS プロセス | | ランタイム | プロセス全体で共有されるグローバル CPython 状態 | | 通訳 | ランタイム内の分離された Python インタープリターの状態 | | スレッドの状態…
-
39. クロージャとセル
#39. クロージャとセル クロージャを使用すると、入れ子になった関数は、囲んでいる関数が返された後、その関数からの変数を使用できます。```python def make_adder(n): def add(x): return x + n return add add10 = make_adder(10) print(add10(5)) 出力: text 15 ```変数 n に属します make_adder 、 しかし add 後でもそれを使用します。 CPython は、キャプチャされた変数をセル オブジェクトに移動することでこれをサポートします。内部関数はそれらのセルへの参照を保持します。 39.1 入れ子関数 ネストされた関数は、別の関数の内部で定義された関数です。```python def outer(): def inner(): return 1 return inner ```の def inner ステートメントが実行されるタイミング outer 走る。関数オブジェクトを作成し、それをローカル名にバインドします。 inner 。 電話をかける outer() その関数オブジェクトを返します。 python fn = outer() print(fn()) の関数オブジェクト inner 含まれるもの: text code object globals dictionary defaults keyword defaults annotations…
-
26. バイトコードの最適化
#26. バイトコードの最適化 バイトコードの最適化は、コード オブジェクトの実行準備が整う前の最後のクリーンアップと改良の段階です。 コンパイラの初期段階で、プログラムの意味が決定され、命令が発行されます。最適化では、Python のセマンティクスを維持しながら、これらの命令をより小さく、よりシンプルに、またはより高速にしようとします。 例えば: python id="u88pli" x = 1 + 2 書かれているかのようにコンパイルできます:```python id="k8v2ef" x = 3 しかし、これは: ``` python id = "lbwhpl" x = a + b ``` 折りたためないので、 ` a ` そして ` b ` は実行時の値です。それらの型は、任意の動作を定義する可能性があります。 `+` 。 ## 26.1 コンパイルパイプラインでの位置 最適化は、最適化の種類に応じて、バイトコード生成後または生成中に行われます。 ``` text id = "olp5um" source ↓ tokenization ↓ parsing ↓ AST ↓ symbol table ↓ instruction generation ↓ optimization ↓ assembly ↓ code…
-
6. ソースコードから実行まで
#6. ソースコードから実行まで CPython は Python ソース テキストを直接実行しません。最初のバイトコード命令が実行される前に、いくつかの内部表現を通じてソース テキストを変換します。 パスは次のとおりです。```text source text ↓ tokens ↓ parse tree ↓ abstract syntax tree ↓ symbol table ↓ code object ↓ frame ↓ bytecode evaluation ↓ object operations ## 6.1 ソーステキスト 入力はテキストとして始まります。 ``` python x = 1 + 2 print ( x ) ``` CPython はこれを実行する前に、次のことを認識している必要があります。 ``` text where statements begin and end which characters form names which characters form numbers which indentation levels…
-
24. 定数、名前、ローカル変数
#24. 定数、名前、ローカル変数 コード オブジェクトは、Python ソース コードをテキストとして保存しません。コンパクトなテーブルと、それらのテーブルをインデックスで参照するバイトコード命令が格納されます。 最も重要なテーブルは次の 3 つです。```text id="mx2a9w" co_consts co_names co_varnames この関数の場合 : ``` python id = "wg80pj" def f ( a ): b = len ( a ) return b + 1 ``` CPython ストア : ``` text id = "jxh1ou" constants : None 1 names : len local variables : a b ``` バイトコード命令はインデックスによってそれらのエントリを参照します。 ## 24.1 コンパイルパイプラインでの位置 定数、名前、およびローカルはコンパイル中にアセンブルされます。 ``` text id = "la84x8" AST ↓ symbol…
-
17. 整数、浮動小数点数、複素数
#17. 整数、浮動小数点、および複素数 Python の数値オブジェクトは、特殊な実装を備えた通常のオブジェクトです。これらは、リスト、辞書、関数、クラス、モジュールと同じオブジェクト モデルに参加します。各値には、オブジェクト ヘッダー、型ポインター、参照カウント動作、および操作用の型スロットがあります。 主な組み込み数値型は次のとおりです。 タイプ Python 名 主な表現 整数 int 任意精度の整数 ブール値 bool のシングルトンサブクラス int 浮動小数点 float Cダブル 複雑な complex C ダブルスのペア これらの型は Python レベルでは単純に見えますが、それぞれに実行時の重要なトレードオフがあります。 17.1 数値オブジェクトはオブジェクトである Python 整数は、通常、生の CPU 整数として Python 変数に格納されません。 python x = 42 CPython レベルでは、 x Python 整数オブジェクトを指します。 概念的には: text x ---> PyLongObject object header integer payload 浮動小数点数と複素数についても同様です。 python a = 1.5 b = 1 + 2j 概念的には:```text a ---> PyFloatObject object header…
-
4. 通訳
章 タイトル 27 評価ループ 28 フレーム 29 スタックベースの実行 30 バイトコードの説明 31 関数呼び出し 32 メソッド呼び出し 33 属性の検索 34 例外処理 35 発電機 36 コルーチンと非同期 37 パターンマッチング 38 内包表記 39 クロージャとセル
-
30. バイトコード命令
#30. バイトコード命令 バイトコード命令は、CPython 評価ループによって実行される操作です。これらは、解析、AST 構築、シンボル分析、コンパイル後の Python コードのコンパクトなインタープリター レベルの形式です。 次のような Python 関数:```python id="ya54lv" def add(a, b): return a + b そのストリームを検査するには、 ` dis ` : ``` python id = "7yf46p" import dis def add ( a , b ): return a + b dis . dis ( add ) ``` 出力は Python のバージョンによって異なりますが、通常は次のような指示が表示されます。 ``` text id = "ot1vx4" LOAD_FAST LOAD_FAST BINARY_OP RETURN_VALUE ``` これらの命令は CPython 仮想マシンの語彙です。 ## 30.1 バイトコード命令とは バイトコード命令は、インタプリタに 1…
-
2. オブジェクトとメモリ
章 タイトル 7 Python オブジェクト モデル 8 PyObject と PyVarObject 9 参照カウント 10 ガベージコレクター 11 メモリ アロケータ 12 オブジェクトのレイアウトとタイプ スロット 13 組み込みオブジェクトの実装 14 文字列、バイト、Unicode 15 リスト、タプル、配列 16 辞書とセット 17 整数、浮動小数点数、複素数
-
2. ソースから CPython を構築する
2. ソースから CPython を構築する ソースから CPython をビルドすると、検査、変更、デバッグ、テストできるローカル インタプリタが得られます。これは、内部構造を真剣に読む前の実際的な最初のステップです。 ソース ビルドを使用すると、パッケージ化された Python インストールでは通常隠蔽されることを行うことができます。```text change interpreter code add debug prints inspect object layout run CPython tests use debug-only assertions trace reference counts debug crashes in C compare bytecode across builds CPython は Git リポジトリに存在します。通常のローカル チェックアウトは次のようになります。 ``` bash git clone https : // github . com / python / cpython . git cd cpython ``` リポジトリには、インタープリタ、標準ライブラリ、テスト、ドキュメント、ビルド ファイル、およびプラットフォーム サポート コードが含まれています。 簡略化したビュー : ``` text…
-
32. メソッド呼び出し
#32. メソッド呼び出し メソッド呼び出しは、通常は属性アクセスで始まる関数呼び出しです。ほとんどのオブジェクトの動作はメソッドを通じて公開されるため、これらは Python のオブジェクト モデルの中心となります。 次のようなメソッド呼び出し: python id="l3owku" obj.method(arg) 1 つの操作のように見えますが、CPython はいくつかの概念的なステップを実行します。```text id="j39rdj" load obj look up attribute method bind obj if needed load arg call the resolved callable return result or raise exception ## 32.1 メソッド呼び出しは属性アクセスと呼び出しである ソース式 : ``` python id = "xgyvgk" obj . method ( 10 ) ``` は次のように理解できます。 ``` python id = "gg912h" tmp = obj . method tmp ( 10 ) ``` これは正しいセマンティック モデルです。属性の検索が最初に行われます。その後、その検索の結果が呼び出されます。…
-
3. コンパイルパイプライン
章 タイトル 18 トークン化 19 解析 20 AST 21 シンボルテーブル 22 コンパイラ パス 23 コードオブジェクト 24 定数、名前、ローカル変数 25 バイトコードの生成 26 バイトコードの最適化
-
4. CPython C コードの読み取り
4. CPython C コードの読み取り CPython C コードを読み取るには、同時に 2 つのメンタル モデルが必要です。 最初のモデルは通常の C: 構造体、ポインター、マクロ、関数ポインター、参照の所有権、割り当て、エラー戻り値、および条件付きコンパイルです。 2 番目のモデルは Python のランタイム モデルです。オブジェクト、型、フレーム、例外、参照カウント、記述子、反復子、モジュール、バイトコードです。 ほとんどの CPython ソース ファイルは両方を組み合わせています。 C コードの行は通常のポインター操作のように見えるかもしれませんが、多くの場合、Python 言語ルールがエンコードされています。 4.1 実行時不変式から開始する 中心となる不変式は単純です。 text id="vm1twr" Every Python value is represented as a PyObject pointer or a pointer to a struct whose first field is compatible with PyObject. ほとんどの CPython 関数は値を処理します。 PyObject * 。```c id="x34zg4" PyObject *obj; 実際の動作はオブジェクトのタイプから決まります。 ``` c id = "y1r4zx" Py_TYPE ( obj…
-
40. モジュールとインポート
#40. モジュールとインポート モジュールは、コードの読み込み、名前空間の分離、再利用の Python の基本単位です。 CPython では、モジュールは言語レベルのオブジェクトであると同時に、インポート システムのランタイム レコードでもあります。 Python レベルでは、モジュールは以下を実行した後に得られるものです。 python import math import os import json インポートされた各名前は、モジュール オブジェクト、パッケージ オブジェクト、関数、クラス、またはその他のエクスポートされたオブジェクトにバインドされます。 CPython レベルでは、インポートはバイトコード命令、インポート フック、モジュール仕様、ローダー、ファインダー、 sys.modules 、パッケージ パス、ファイル システム ルックアップ、バイトコード キャッシュ、インポート ロック、モジュールの実行。 インポート システムは、単純なファイル インクルード メカニズムではありません。ランタイムプロトコルです。 40.1 モジュールとは何か モジュールは次のタイプのオブジェクトです。 module 。```python import sys print(type(sys)) print(sys. name ) 出力: text <class 'module'> sys モジュール オブジェクトは辞書を所有します。その辞書はモジュールのグローバル名前空間です。 python import math print(math. dict ["pi"]) print(math. dict ["sqrt"]) という名前のファイルの場合、 ` config . py ` : ```…
-
19. 解析
#19. 解析 解析は、トークン ストリームを構文構造に変換する段階です。 トークナイザーは語彙単位を認識します。パーサーは文法構造を認識します。一連のトークンが有効な Python プログラムであるかどうかを判断し、有効な場合は抽象構文ツリーを構築します。 このソースの場合: python def add(a, b): return a + b トークナイザーは次のようなトークンを生成します。 text NAME "def" NAME "add" LPAR "(" NAME "a" COMMA "," NAME "b" RPAR ")" COLON ":" NEWLINE "\n" INDENT " " NAME "return" NAME "a" PLUS "+" NAME "b" NEWLINE "\n" DEDENT "" ENDMARKER "" パーサーはこれらのトークン構造を次のように与えます。 text Module FunctionDef name="add" arguments arg "a" arg "b" body Return BinOp Name "a" Add Name…
-
7. Python オブジェクト モデル
#7. Python オブジェクト モデル Python オブジェクト モデルは CPython の基礎です。 Python で実行されるものはすべて、整数、文字列、リスト、モジュール、関数、クラス、例外、フレーム、さらにはコンパイルされたコードなど、最終的にはオブジェクトに対する操作になります。 言語レベルでは、Python はすべてのオブジェクトに ID、型、および値があると言います。オブジェクトのアイデンティティは作成後も固定されます。 is アイデンティティを比較し、 id() その ID を表す整数を返します。 ([Python ドキュメント][1]) CPython は、C 構造体、オブジェクト ヘッダー、参照カウント、型オブジェクト、および操作スロットを使用してこのモデルを実装します。 7.1 オブジェクト、値、およびアイデンティティ Python オブジェクトには 3 つのコア プロパティがあります。 プロパティ 意味 例 アイデンティティ オブジェクトの安定したアイデンティティ id(x) タイプ オブジェクトのランタイムタイプ type(x) 値 オブジェクト によって表されるデータ 42 、 "abc" 、 [1, 2] 例:```python x = [1, 2, 3] y = x print(x is y) # True print(type(x)) # <class 'list'> print(x)…
-
13. 組み込みオブジェクトの実装
#13. 組み込みオブジェクトの実装 組み込みオブジェクトは、Python のコア型の背後にある具体的なデータ構造です。これらは、ID、型、参照カウント、サポートされている場合は属性、および型スロットによって定義された動作を持つという意味では、通常の Python オブジェクトです。これらは、ストレージと操作が C で直接実装されているため、特別です。 この章では大まかな地図を示します。後の章では、文字列、リスト、タプル、辞書、セット、数値、関数、モジュール、およびフレームについてさらに詳しく説明します。 13.1 組み込みは型オブジェクトです などの内蔵タイプ list 、 dict 、 または int それ自体は Python オブジェクトです。 python print(type(list)) # <class 'type'> print(type(dict)) # <class 'type'> print(type(int)) # <class 'type'> インスタンスはその型オブジェクトを指します。 python xs = [1, 2, 3] print(type(xs)) # <class 'list'> C レベルでは:```text xs ---> PyListObject ob_refcnt ob_type ----> PyList_Type ob_size ob_item allocated ## 13.2 組み込みが C で実装される理由 組み込み型は、 Python 実行の最もホットなパスにあります。 一般的な操作は次のとおりです。 ``` text integer arithmetic…
-
44. クラスとメタクラス
#44. クラスとメタクラス クラスは、Python オブジェクト モデルを通じてインスタンスを作成し、属性を保存し、継承に参加し、動作を定義するランタイム オブジェクトです。 CPython では、クラスは通常、型が次のようなオブジェクトです。 type 。 メタクラスはクラスのクラスです。これは、クラス オブジェクトの作成、初期化、表現、呼び出しの方法を制御します。 通常クラスの場合:```python id="g3fkzi" class User: pass print(type(User)) 出力: text id="iqt3cc" <class 'type'> ```これはつまり User はオブジェクトであり、その型は type 。 44.1 クラスはオブジェクトである クラス定義によりクラス オブジェクトが作成されます。```python id="8zc5m6" class User: name = "anonymous" def hello(self): return "hello" 処刑後は、`User`周囲の名前空間にバインドされた通常の名前です。 python id="rx6c1m" print(User) print(type(User)) print(User. name ) print(User. dict ) クラス オブジェクトには次のような属性が格納されます。 text id="xxewj0" name qualname module dict bases mro methods descriptors class variables annotations ## 44.2…
-
27. 評価ループ
#27. 評価ループ 評価ループは、CPython の中心的な実行エンジンです。コンパイルされたコード オブジェクトを取得し、そのバイトコード命令を実行して、結果または例外を生成します。 大まかに言うと、CPython の実行は次のようになります。```text Python source ↓ tokens ↓ parser ↓ AST ↓ symbol table ↓ compiler ↓ code object ↓ frame ↓ evaluation loop ↓ Python result or exception 評価ループは CPython のインタプリタ実装内に存在します。歴史的に、キー ファイルは ` Python / ceval . c ` 、周囲のインタプリタ機構が他のファイルに分散されています。最新の CPython は、バイトコード定義からいくつかのインタープリター コードも生成します。詳細はリリース間で変化しますが、モデルは安定しています。フレームはバイトコード命令を繰り返しディスパッチすることでコード オブジェクトを実行します。このコードはバージョン間で変更されるため、 CPython 独自の開発者ガイドでは、現在の参照として内部ドキュメントとソース ツリーを示しています。 ## 27.1 評価ループの仕事 評価ループは Python テキストを解析しません。 AST は構築されません。通常、語彙の範囲は決定されません。これらのジョブは、実行が開始されるまでにすでに終了しています。 その仕事はより狭く、より機械的です。 ``` text read the next bytecode instruction decode its…
-
11. メモリ アロケータ
#11. メモリアロケータ CPython はメモリを常に割り当てます。すべての整数オブジェクト、リスト オブジェクト、フレーム、タプル、辞書エントリ配列、文字列バッファ、コード オブジェクト、例外、モジュール、関数にはメモリが必要です。アロケータ システムは、これらの割り当てを高速かつ構造化し、デバッグ可能にし、プラットフォーム間で移植できるようにするために存在します。 CPython はアロケーターを 1 つだけ使用するわけではありません。複数のアロケーター ドメインとレイヤーを使用します。小さな Python オブジェクトは、CPython の特殊な小さなオブジェクト アロケーターを通過することがよくありますが、より大きなバッファーはプラットフォーム アロケーターを通過する場合があります。 11.1 CPython が独自のアロケータを持つ理由 Python プログラムは、有効期間の短いオブジェクトを多数作成します。 python for i in range(1_000_000): x = (i, i + 1) このループは、多くのタプル オブジェクトと整数参照を割り当てます。すべての小さなオブジェクトの割り当てがシステムに直接行われる場合 malloc 、オーバーヘッドが高くなります。 CPython のアロケーター システムは、次のようにしてこれを改善します。```text serving small object allocations quickly grouping small allocations into arenas and pools reducing calls into the platform allocator supporting debug hooks separating allocator domains making object allocation behavior predictable enough…
-
37. パターンマッチング
#37. パターンマッチング パターン マッチングは Python の構造マッチング システムです。それを実装するのは、 match 声明と case 条項。```python match value: case 0: result = "zero" case [x, y]: result = x + y case {"name": name}: result = name case _: result = None CPython レベルでは、パターン マッチングは通常のバイトコードと特殊なマッチング命令にコンパイルされます。インタプリタはサブジェクトを評価し、各ケースを順番に試し、一致が成功した場合に名前をバインドし、選択された本文にジャンプします。 ## 37.1`match`声明 あ ` match ` ステートメントには 1 つの主語式と 1 つ以上のケースがあります。 ``` python match subject : case pattern : body case pattern if guard : body case _ : body…