tag

#cpython

55 pages tagged

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"…

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)) ```言語レベルの…

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 リストには、…

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…

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 トークナイザーを使用します。一般の人々…

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 ` : ```…

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)…

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…

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 インタープリターの状態 | | スレッドの状態…

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…

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…

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…

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…

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/`|ドキュメントのソース |…

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…

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 コードオブジェクトと関数オブジェクト 関数オブジェクトはコード オブジェクトをラップします。 例:…

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 すべてのオブジェクトが同じように始まる理由 次の…