序章
アプリケーションプログラマーのPythonへのインターフェイスにより、CおよびC ++プログラマーは、さまざまなレベルでPythonインタープリターにアクセスできます。 APIはC ++からも同様に使用できますが、簡潔にするために、一般にPython / CAPIと呼ばれます。 Python / C APIを使用する理由は、根本的に2つあります。 最初の理由は、特定の目的のために拡張モジュールを作成することです。 これらは、Pythonインタープリターを拡張するCモジュールです。 これはおそらく最も一般的な使用法です。 2番目の理由は、Pythonをより大きなアプリケーションのコンポーネントとして使用することです。 この手法は、一般に、アプリケーションへの埋め込み Pythonと呼ばれます。
拡張モジュールの作成は比較的よく理解されているプロセスであり、「クックブック」アプローチが適切に機能します。 プロセスをある程度自動化するツールがいくつかあります。 人々はPythonの初期の存在以来、他のアプリケーションにPythonを組み込んでいますが、Pythonを埋め込むプロセスは、拡張機能を作成するよりも簡単ではありません。
多くのAPI関数は、Pythonを埋め込むか拡張するかに関係なく便利です。 さらに、Pythonを埋め込むほとんどのアプリケーションは、カスタム拡張機能も提供する必要があるため、実際のアプリケーションにPythonを埋め込む前に、拡張機能の作成に慣れておくことをお勧めします。
コーディング基準
CPythonに含めるCコードを作成する場合は、 PEP 7 で定義されているガイドラインと標準に従う必要があります。 これらのガイドラインは、貢献しているPythonのバージョンに関係なく適用されます。 これらの規則に従うことは、最終的にPythonに貢献することを期待しない限り、独自のサードパーティ拡張モジュールには必要ありません。
ファイルを含める
Python / C APIを使用するために必要なすべての関数、型、およびマクロの定義は、次の行によってコードに含まれています。
#define PY_SSIZE_T_CLEAN
#include <Python.h>
これは、次の標準ヘッダーが含まれていることを意味します:<stdio.h>
、<string.h>
、<errno.h>
、<limits.h>
、<assert.h>
、<stdlib.h>
(可能な場合は)。
ノート
Pythonは、一部のシステムの標準ヘッダーに影響を与えるプリプロセッサ定義を定義する場合があるため、標準ヘッダーを含める前に、 Python.h
を含める必要があります。
Python.h
を含める前に、常にPY_SSIZE_T_CLEAN
を定義することをお勧めします。 このマクロの説明については、引数の解析と値の構築を参照してください。
Python.hで定義されているすべてのユーザーに表示される名前(含まれている標準ヘッダーで定義されている名前を除く)には、プレフィックスPy
または_Py
のいずれかが付いています。 _Py
で始まる名前は、Python実装による内部使用のためのものであり、拡張機能の作成者は使用しないでください。 構造体メンバー名には、予約済みの接頭辞がありません。
ノート
ユーザーコードでは、Py
または_Py
で始まる名前を定義しないでください。 これは読者を混乱させ、ユーザーコードの将来のPythonバージョンへの移植性を危険にさらします。これにより、これらのプレフィックスの1つで始まる追加の名前が定義される可能性があります。
ヘッダーファイルは通常、Pythonでインストールされます。 Unixでは、これらはディレクトリprefix/include/pythonversion/
およびexec_prefix/include/pythonversion/
にあり、 prefix
および exec_prefix
は次のとおりです。 Pythonの configure スクリプトに対応するパラメーターによって定義されます。バージョンは'%d.%d' % sys.version_info[:2]
です。 Windowsでは、ヘッダーはprefix/include
にインストールされます。ここで、 prefix
は、インストーラーに指定されたインストールディレクトリです。
ヘッダーを含めるには、コンパイラのインクルードの検索パスに両方のディレクトリ(異なる場合)を配置します。 しない親ディレクトリを検索パスに配置してから、#include <pythonX.Y/Python.h>
を使用します。 prefix
の下のプラットフォームに依存しないヘッダーには、 exec_prefix
のプラットフォーム固有のヘッダーが含まれているため、これはマルチプラットフォームビルドでは機能しません。
C ++ユーザーは、APIは完全にCを使用して定義されていますが、ヘッダーファイルはエントリポイントをextern "C"
として適切に宣言していることに注意してください。 その結果、C ++のAPIを使用するために特別なことをする必要はありません。
便利なマクロ
Pythonヘッダーファイルには、いくつかの便利なマクロが定義されています。 多くは、有用な場所の近くで定義されています(例: Py_RETURN_NONE )。 より一般的なユーティリティの他のものはここで定義されます。 これは必ずしも完全なリストではありません。
- Py_UNREACHABLE()
到達する予定のないコードパスがある場合にこれを使用します。 たとえば、
switch
ステートメントのdefault:
句では、すべての可能な値がcase
ステートメントでカバーされています。assert(0)
またはabort()
の電話をかけたくなるような場所でこれを使用します。バージョン3.7の新機能。
- Py_ABS(x)
x
の絶対値を返します。バージョン3.3の新機能。
- Py_MIN(x, y)
x
とy
の間の最小値を返します。バージョン3.3の新機能。
- Py_MAX(x, y)
x
とy
の間の最大値を返します。バージョン3.3の新機能。
- Py_STRINGIFY(x)
x
をC文字列に変換します。 例えばPy_STRINGIFY(123)
は"123"
を返します。バージョン3.4の新機能。
- Py_MEMBER_SIZE(type, member)
構造体のサイズ(
type
)member
をバイト単位で返します。バージョン3.6の新機能。
- Py_CHARMASK(c)
- 引数は、[-128、127]または[0、255]の範囲の文字または整数である必要があります。 このマクロは、
unsigned char
にキャストされたc
を返します。
- Py_GETENV(s)
getenv(s)
と同様ですが、 -E がコマンドラインで渡された場合(つまり、NULL
を返します)Py_IgnoreEnvironmentFlag
が設定されている場合)。
- Py_UNUSED(arg)
これを関数定義の未使用の引数に使用して、コンパイラの警告を消します。
PyObject* func(PyObject *Py_UNUSED(ignored))
。バージョン3.4の新機能。
- PyDoc_STRVAR(name, str)
docstringで使用できる
name
という名前の変数を作成します。 Pythonがdocstringなしでビルドされている場合、値は空になります。PEP 7 で指定されているように、docstringに PyDoc_STRVAR を使用して、docstringなしでPythonを構築できるようにします。
例:
PyDoc_STRVAR(pop_doc, "Remove and return the rightmost element."); static PyMethodDef deque_methods[] = { // ... {"pop", (PyCFunction)deque_pop, METH_NOARGS, pop_doc}, // ... }
- PyDoc_STR(str)
指定された入力文字列のdocstringを作成するか、docstringが無効になっている場合は空の文字列を作成します。
[[#c.PyDoc_STR|]] PEP 7 で指定されているように、 PyDoc_STR を使用して、docstringなしでPythonの構築をサポートするdocstringを指定します。
例:
static PyMethodDef pysqlite_row_methods[] = { {"keys", (PyCFunction)pysqlite_row_keys, METH_NOARGS, PyDoc_STR("Returns the keys of the row.")}, {NULL, NULL} };
オブジェクト、タイプ、参照数
ほとんどのPython / C API関数には、1つ以上の引数と、PyObject*
型の戻り値があります。 この型は、任意のPythonオブジェクトを表す不透明(OPAQUE)型へのポインターです。 すべてのPythonオブジェクトタイプはほとんどの状況(割り当て、スコープルール、引数の受け渡しなど)でPython言語によって同じように扱われるため、単一のCタイプで表すのが適切です。 ほとんどすべてのPythonオブジェクトがヒープ上に存在します。 PyObject 型の自動変数または静的変数を宣言することはなく、PyObject*
型のポインター変数のみを宣言できます。 唯一の例外は型オブジェクトです。 これらは割り当てを解除してはならないため、通常は静的 PyTypeObject オブジェクトです。
すべてのPythonオブジェクト(Python整数も含む)には、タイプと参照カウントがあります。 オブジェクトの型によって、オブジェクトの種類が決まります(たとえば、整数、リスト、またはユーザー定義関数。標準の型階層で説明されているように、さらに多くのオブジェクトがあります)。 よく知られているタイプごとに、オブジェクトがそのタイプであるかどうかを確認するマクロがあります。 たとえば、PyList_Check(a)
は、 a が指すオブジェクトがPythonリストである場合にのみ、真になります。
参照カウント
今日のコンピュータのメモリサイズは有限である(そしてしばしば厳しく制限されている)ため、参照カウントは重要です。 オブジェクトへの参照がある場所がいくつあるかをカウントします。 このような場所は、別のオブジェクト、グローバル(または静的)C変数、または一部のC関数のローカル変数である可能性があります。 オブジェクトの参照カウントがゼロになると、オブジェクトの割り当てが解除されます。 他のオブジェクトへの参照が含まれている場合、それらの参照カウントはデクリメントされます。 これらの他のオブジェクトは、このデクリメントによって参照カウントがゼロになった場合などに、順番に割り当てが解除される可能性があります。 (ここで相互に参照するオブジェクトには明らかな問題があります。今のところ、解決策は「それをしない」ことです。)
参照カウントは常に明示的に操作されます。 通常の方法は、マクロ Py_INCREF()を使用してオブジェクトの参照カウントを1つインクリメントし、 Py_DECREF()を使用してオブジェクトを1つデクリメントすることです。 Py_DECREF()マクロは、参照カウントがゼロになるかどうかをチェックしてからオブジェクトのデアロケーターを呼び出す必要があるため、increfマクロよりもかなり複雑です。 デアロケーターは、オブジェクトの型構造に含まれる関数ポインターです。 タイプ固有のデロケーターは、これがリストなどの複合オブジェクトタイプである場合、オブジェクトに含まれる他のオブジェクトの参照カウントをデクリメントし、必要な追加のファイナライズを実行します。 参照カウントがオーバーフローする可能性はありません。 少なくとも、仮想メモリ内の個別のメモリ位置と同じ数のビットが参照カウントを保持するために使用されます(sizeof(Py_ssize_t) >= sizeof(void*)
を想定)。 したがって、参照カウントの増分は簡単な操作です。
オブジェクトへのポインタを含むすべてのローカル変数について、オブジェクトの参照カウントをインクリメントする必要はありません。 理論的には、オブジェクトの参照カウントは、変数がオブジェクトを指すようになると1つ増え、変数がスコープ外になると1つ減ります。 ただし、これら2つは互いに打ち消し合うため、最終的に参照カウントは変更されていません。 参照カウントを使用する唯一の本当の理由は、変数がオブジェクトを指している限り、オブジェクトの割り当てが解除されないようにすることです。 少なくとも変数と同じ長さのオブジェクトへの参照が少なくとも1つあることがわかっている場合は、参照カウントを一時的にインクリメントする必要はありません。 これが発生する重要な状況は、Pythonから呼び出される拡張モジュールのC関数に引数として渡されるオブジェクトにあります。 呼び出しメカニズムは、呼び出しの間、すべての引数への参照を保持することを保証します。
ただし、よくある落とし穴は、リストからオブジェクトを抽出し、参照カウントを増やさずにしばらく保持することです。 他の操作によって、オブジェクトがリストから削除され、参照カウントが減り、割り当てが解除される可能性があります。 本当の危険は、無実に見える操作がこれを行う可能性のある任意のPythonコードを呼び出す可能性があることです。 Py_DECREF()からユーザーに制御を戻すことができるコードパスがあるため、ほとんどすべての操作が潜在的に危険です。
安全なアプローチは、常に一般的な操作(名前がPyObject_
、PyNumber_
、PySequence_
、またはPyMapping_
で始まる関数)を使用することです。 これらの操作は、返すオブジェクトの参照カウントを常にインクリメントします。 これにより、呼び出し元は、結果が完了したときに Py_DECREF()を呼び出す責任があります。 これはすぐに第二の性質になります。
参照カウントの詳細
Python / C APIの関数の参照カウントの動作は、参照の所有権の観点から最もよく説明されています。 所有権は参照に関係し、オブジェクトには関係しません(オブジェクトは所有されません。常に共有されます)。 「参照を所有する」とは、参照が不要になったときにPy_DECREFを呼び出す責任があることを意味します。 所有権を譲渡することもできます。つまり、参照の所有権を受け取ったコードは、参照がなくなったときに Py_DECREF()または Py_XDECREF()を呼び出すことにより、最終的に参照を拒否する責任を負います。必要な場合、またはこの責任を(通常は呼び出し元に)渡す。 関数が参照の所有権を呼び出し元に渡すと、呼び出し元は new 参照を受信したと言われます。 所有権が譲渡されない場合、発信者は参照を借用すると言われます。 借用した参照に対して何もする必要はありません。
逆に、呼び出し元の関数がオブジェクトへの参照を渡す場合、2つの可能性があります。関数がオブジェクトへの参照を盗むか、そうでないかです。 参照の盗用は、関数への参照を渡すと、その関数はその参照を所有していると見なし、ユーザーはその参照に対して責任を負わないことを意味します。
参照を盗む関数はほとんどありません。 2つの注目すべき例外は、 PyList_SetItem()と PyTuple_SetItem()です。これらは、アイテムへの参照を盗みます(ただし、アイテムが配置されるタプルまたはリストへの参照は盗みません!)。 これらの関数は、タプルまたはリストに新しく作成されたオブジェクトを取り込むための一般的なイディオムのために、参照を盗むように設計されています。 たとえば、タプル(1, 2, "three")
を作成するコードは、次のようになります(今のところエラー処理を忘れています。これをコーディングするためのより良い方法を以下に示します)。
PyObject *t;
t = PyTuple_New(3);
PyTuple_SetItem(t, 0, PyLong_FromLong(1L));
PyTuple_SetItem(t, 1, PyLong_FromLong(2L));
PyTuple_SetItem(t, 2, PyUnicode_FromString("three"));
ここで、 PyLong_FromLong()は、 PyTuple_SetItem()によってすぐに盗まれる新しい参照を返します。 オブジェクトへの参照が盗まれてもオブジェクトを使い続けたい場合は、 Py_INCREF()を使用して別の参照を取得してから、参照を盗む関数を呼び出します。
ちなみに、 PyTuple_SetItem()は、タプルアイテムを設定するのみの方法です。 PySequence_SetItem()および PyObject_SetItem()は、タプルが不変のデータ型であるため、これを拒否します。 PyTuple_SetItem()は、自分で作成するタプルにのみ使用してください。
リストにデータを入力するための同等のコードは、 PyList_New()および PyList_SetItem()を使用して記述できます。
ただし、実際には、タプルまたはリストを作成してデータを設定するこれらの方法を使用することはめったにありません。 形式の文字列によって指示された、C値から最も一般的なオブジェクトを作成できる汎用関数 Py_BuildValue()があります。 たとえば、上記の2つのコードブロックは、次のように置き換えることができます(エラーチェックも処理します)。
PyObject *tuple, *list;
tuple = Py_BuildValue("(iis)", 1, 2, "three");
list = Py_BuildValue("[iis]", 1, 2, "three");
PyObject_SetItem()や、作成している関数に渡された引数など、参照のみを借用しているアイテムと友達を使用するのがはるかに一般的です。 その場合、参照カウントをインクリメントする必要がないため、参照を提供する(「盗まれる」)ことができるため、参照カウントに関する彼らの行動は非常に賢明です。 たとえば、この関数は、リストのすべてのアイテム(実際には任意の可変シーケンス)を特定のアイテムに設定します。
int
set_all(PyObject *target, PyObject *item)
{
Py_ssize_t i, n;
n = PyObject_Length(target);
if (n < 0)
return -1;
for (i = 0; i < n; i++) {
PyObject *index = PyLong_FromSsize_t(i);
if (!index)
return -1;
if (PyObject_SetItem(target, index, item) < 0) {
Py_DECREF(index);
return -1;
}
Py_DECREF(index);
}
return 0;
}
関数の戻り値では状況が少し異なります。 ほとんどの関数への参照の受け渡しは、その参照の所有権の責任を変更しませんが、オブジェクトへの参照を返す多くの関数は、参照の所有権を与えます。 理由は単純です。多くの場合、返されるオブジェクトはその場で作成され、取得する参照はオブジェクトへの唯一の参照です。 したがって、 PyObject_GetItem()や PySequence_GetItem()などのオブジェクト参照を返すジェネリック関数は、常に新しい参照を返します(呼び出し元が参照の所有者になります)。
関数によって返される参照を所有しているかどうかは、呼び出す関数のみに依存することを理解することが重要です— 羽毛(関数に引数として渡されるオブジェクトのタイプ)はありません。 したがって、 PyList_GetItem()を使用してリストからアイテムを抽出する場合、参照を所有していませんが、[Xを使用して同じリストから同じアイテムを取得する場合X404X] PySequence_GetItem()(これはたまたままったく同じ引数を取ります)、返されたオブジェクトへの参照を所有しています。
これは、整数のリスト内の項目の合計を計算する関数を作成する方法の例です。 1回は PyList_GetItem()を使用し、もう1回は PySequence_GetItem()を使用します。
long
sum_list(PyObject *list)
{
Py_ssize_t i, n;
long total = 0, value;
PyObject *item;
n = PyList_Size(list);
if (n < 0)
return -1; /* Not a list */
for (i = 0; i < n; i++) {
item = PyList_GetItem(list, i); /* Can't fail */
if (!PyLong_Check(item)) continue; /* Skip non-integers */
value = PyLong_AsLong(item);
if (value == -1 && PyErr_Occurred())
/* Integer too big to fit in a C long, bail out */
return -1;
total += value;
}
return total;
}
long
sum_sequence(PyObject *sequence)
{
Py_ssize_t i, n;
long total = 0, value;
PyObject *item;
n = PySequence_Length(sequence);
if (n < 0)
return -1; /* Has no length */
for (i = 0; i < n; i++) {
item = PySequence_GetItem(sequence, i);
if (item == NULL)
return -1; /* Not a sequence, or other failure */
if (PyLong_Check(item)) {
value = PyLong_AsLong(item);
Py_DECREF(item);
if (value == -1 && PyErr_Occurred())
/* Integer too big to fit in a C long, bail out */
return -1;
total += value;
}
else {
Py_DECREF(item); /* Discard reference ownership */
}
}
return total;
}
種類
Python / CAPIで重要な役割を果たす他のデータ型はほとんどありません。 ほとんどは、int
、long
、double
、char*
などの単純なCタイプです。 いくつかの構造タイプは、モジュールによってエクスポートされた関数または新しいオブジェクトタイプのデータ属性を一覧表示するために使用される静的テーブルを記述するために使用され、別の構造タイプは、複素数の値を記述するために使用されます。 これらについては、それらを使用する関数とともに説明します。
例外
Pythonプログラマーは、特定のエラー処理が必要な場合にのみ例外を処理する必要があります。 未処理の例外は、トップレベルのインタープリターに到達するまで、呼び出し元に自動的に伝播され、次に呼び出し元の呼び出し元に伝播され、スタックトレースバックを伴ってユーザーに報告されます。
ただし、Cプログラマーの場合、エラーチェックは常に明示的に行う必要があります。 Python / C APIのすべての関数は、関数のドキュメントで明示的な主張がない限り、例外を発生させる可能性があります。 一般に、関数でエラーが発生すると、関数は例外を設定し、所有しているオブジェクト参照を破棄して、エラーインジケーターを返します。 特に文書化されていない場合、このインジケーターは、関数の戻りタイプに応じて、NULL
または-1
のいずれかになります。 いくつかの関数はブール値のtrue / falseの結果を返し、falseはエラーを示します。 明示的なエラーインジケータを返さない、またはあいまいな戻り値を持つ関数はほとんどなく、 PyErr_Occurred()を使用してエラーを明示的にテストする必要があります。 これらの例外は常に明示的に文書化されています。
例外状態はスレッドごとのストレージで維持されます(これは、スレッド化されていないアプリケーションでグローバルストレージを使用するのと同じです)。 スレッドは、例外が発生したかどうかという2つの状態のいずれかになります。 関数 PyErr_Occurred()を使用して、これをチェックできます。例外が発生した場合は例外タイプオブジェクトへの借用参照を返し、それ以外の場合はNULL
を返します。 例外状態を設定する関数はいくつかあります。 PyErr_SetString()は例外状態を設定する最も一般的な(最も一般的ではありませんが)関数であり、 PyErr_Clear()はクリアします。例外状態。
完全な例外状態は、例外タイプ、対応する例外値、およびトレースバックの3つのオブジェクト(すべてNULL
の場合があります)で構成されます。 これらは、sys.exc_info()
のPythonの結果と同じ意味を持ちます。 ただし、それらは同じではありません。Pythonオブジェクトは、Python try … except ステートメントによって処理される最後の例外を表しますが、Cレベルの例外状態は例外が発生している間のみ存在します。 Pythonバイトコードインタープリターのメインループに到達するまでC関数間で受け渡され、sys.exc_info()
およびその仲間への転送を処理します。
Python 1.5以降、Pythonコードから例外状態にアクセスするための推奨されるスレッドセーフな方法は、関数 sys.exc_info()を呼び出すことです。この関数は、Pythonコードのスレッドごとの例外状態を返します。 。 また、例外状態にアクセスする両方の方法のセマンティクスが変更され、例外をキャッチする関数がスレッドの例外状態を保存および復元して、呼び出し元の例外状態を保持するようになりました。 これにより、処理中の例外を無害に見える関数が上書きすることによって引き起こされる、例外処理コードの一般的なバグを防ぎます。 また、トレースバックのスタックフレームによって参照されるオブジェクトの不要なライフタイム延長も削減されます。
一般的な原則として、別の関数を呼び出してタスクを実行する関数は、呼び出された関数が例外を発生させたかどうかを確認し、発生した場合は、例外状態を呼び出し元に渡す必要があります。 所有しているオブジェクト参照を破棄し、エラーインジケータを返す必要がありますが、は別の例外を設定しないでくださいは、発生したばかりの例外を上書きし、の正確な原因に関する重要な情報を失います。エラー。
上記のsum_sequence()
の例に、例外を検出して渡す簡単な例を示します。 この例では、エラーを検出したときに、所有している参照をクリーンアップする必要がない場合があります。 次の関数例は、エラーのクリーンアップを示しています。 まず、Pythonが好きな理由を思い出させるために、同等のPythonコードを示します。
def incr_item(dict, key):
try:
item = dict[key]
except KeyError:
item = 0
dict[key] = item + 1
これが対応するCコードです。
int
incr_item(PyObject *dict, PyObject *key)
{
/* Objects all initialized to NULL for Py_XDECREF */
PyObject *item = NULL, *const_one = NULL, *incremented_item = NULL;
int rv = -1; /* Return value initialized to -1 (failure) */
item = PyObject_GetItem(dict, key);
if (item == NULL) {
/* Handle KeyError only: */
if (!PyErr_ExceptionMatches(PyExc_KeyError))
goto error;
/* Clear the error and use zero: */
PyErr_Clear();
item = PyLong_FromLong(0L);
if (item == NULL)
goto error;
}
const_one = PyLong_FromLong(1L);
if (const_one == NULL)
goto error;
incremented_item = PyNumber_Add(item, const_one);
if (incremented_item == NULL)
goto error;
if (PyObject_SetItem(dict, key, incremented_item) < 0)
goto error;
rv = 0; /* Success */
/* Continue with cleanup code */
error:
/* Cleanup code, shared by success and failure path */
/* Use Py_XDECREF() to ignore NULL references */
Py_XDECREF(item);
Py_XDECREF(const_one);
Py_XDECREF(incremented_item);
return rv; /* -1 for error, 0 for success */
}
この例は、Cでのgoto
ステートメントの承認された使用法を表しています。 これは、 PyErr_ExceptionMatches()および PyErr_Clear()を使用して特定の例外を処理する方法と、 Py_XDECREF()を使用して所有されている参照を破棄する方法を示しています。 NULL
(名前の'X'
に注意してください。 Py_DECREF()は、NULL
参照に直面するとクラッシュします)。 これが機能するためには、所有されている参照を保持するために使用される変数がNULL
に初期化されていることが重要です。 同様に、提案された戻り値は-1
(失敗)に初期化され、最後の呼び出しが成功した後にのみ成功に設定されます。
Pythonの埋め込み
Pythonインタープリターの(拡張ライターではなく)埋め込み者だけが心配する必要がある1つの重要なタスクは、Pythonインタープリターの初期化、場合によっては最終化です。 インタープリターのほとんどの機能は、インタープリターが初期化された後にのみ使用できます。
基本的な初期化関数は Py_Initialize()です。 これにより、ロードされたモジュールのテーブルが初期化され、基本モジュール builtins 、 __ main __ 、および sys が作成されます。 また、モジュール検索パス(sys.path
)を初期化します。
Py_Initialize()は、「スクリプト引数リスト」(sys.argv
)を設定しません。 この変数が後で実行されるPythonコードで必要な場合は、 Py_Initialize()を呼び出した後、PySys_SetArgvEx(argc, argv, updatepath)
を呼び出して明示的に設定する必要があります。
ほとんどのシステム(特にUnixとWindowsでは、詳細は少し異なりますが)では、 Py_Initialize()は、標準のPythonインタープリター実行可能ファイルの場所の最良の推測に基づいてモジュール検索パスを計算します。 PythonライブラリがPythonインタプリタ実行可能ファイルに対して固定された場所にあること。 特に、シェルコマンド検索パス(環境変数 PATH
)。
たとえば、Python実行可能ファイルが/usr/local/bin/python
にある場合、ライブラリは/usr/local/lib/pythonX.Y
にあると見なされます。 (実際、この特定のパスは「フォールバック」の場所でもあり、python
という名前の実行可能ファイルが PATH
に沿って見つからない場合に使用されます。)ユーザーはこの動作をオーバーライドできます。環境変数 PYTHONHOME を設定するか、 PYTHONPATH を設定して標準パスの前に追加のディレクトリを挿入します。
埋め込みアプリケーションは、Py_SetProgramName(file)
before を呼び出して Py_Initialize()を呼び出すことにより、検索を操作できます。 PYTHONHOME は引き続きこれをオーバーライドし、 PYTHONPATH は引き続き標準パスの前に挿入されることに注意してください。 完全な制御が必要なアプリケーションは、 Py_GetPath()、 Py_GetPrefix()、 Py_GetExecPrefix()、および Py_GetProgramFullPath()の独自の実装を提供する必要があります(すべてModules/getpath.c
で定義されています)。
Pythonを「初期化解除」することが望ましい場合があります。 たとえば、アプリケーションで最初からやり直す( Py_Initialize()をもう一度呼び出す)場合や、アプリケーションがPythonを使用して実行され、Pythonによって割り当てられたメモリを解放したい場合があります。 これは、 Py_FinalizeEx()を呼び出すことで実行できます。 関数 Py_IsInitialized()は、Pythonが現在初期化された状態にある場合、trueを返します。 これらの関数の詳細については、後の章で説明します。 Py_FinalizeEx()は、Pythonインタープリターによって割り当てられたすべてのメモリを解放しないことに注意してください。 現在、拡張モジュールによって割り当てられたメモリを解放することはできません。
ビルドのデバッグ
Pythonは、インタプリタと拡張モジュールの追加チェックを可能にするために、いくつかのマクロで構築できます。 これらのチェックはランタイムに大量のオーバーヘッドを追加する傾向があるため、デフォルトでは有効になっていません。
さまざまなタイプのデバッグビルドの完全なリストは、PythonソースディストリビューションのファイルMisc/SpecialBuilds.txt
にあります。 参照カウントのトレース、メモリアロケータのデバッグ、またはメインインタプリタループの低レベルプロファイリングをサポートするビルドが利用可能です。 このセクションの残りの部分では、最も頻繁に使用されるビルドについてのみ説明します。
定義されたPy_DEBUG
マクロを使用してインタープリターをコンパイルすると、Pythonの「デバッグビルド」が一般的に意味するものが生成されます。 Py_DEBUG
は、--with-pydebug
を./configure
コマンドに追加することにより、Unixビルドで有効になります。 また、Python固有ではない_DEBUG
マクロの存在によっても暗示されます。 UnixビルドでPy_DEBUG
が有効になっている場合、コンパイラの最適化は無効になります。
以下で説明する参照カウントのデバッグに加えて、次の追加のチェックが実行されます。
- 追加のチェックがオブジェクトアロケータに追加されます。
- パーサーとコンパイラーに追加のチェックが追加されます。
- ワイドタイプからナロータイプへのダウンキャストは、情報の損失がないかチェックされます。
- 多数のアサーションがディクショナリに追加され、実装が設定されます。 さらに、設定されたオブジェクトは
test_c_api()
メソッドを取得します。 - 入力引数の健全性チェックがフレーム作成に追加されます。
- intのストレージは、初期化されていない数字への参照をキャッチするために、既知の無効なパターンで初期化されます。
- 低レベルのトレースと追加の例外チェックがランタイム仮想マシンに追加されます。
- メモリアリーナの実装に追加のチェックが追加されます。
- スレッドモジュールに追加のデバッグが追加されます。
ここに記載されていない追加のチェックがある場合があります。
Py_TRACE_REFS
を定義すると、参照トレースが有効になります。 定義すると、すべての PyObject に2つのフィールドを追加することにより、アクティブオブジェクトの循環二重リンクリストが維持されます。 合計割り当ても追跡されます。 終了すると、既存のすべての参照が印刷されます。 (インタラクティブモードでは、これはインタプリタによって実行されるすべてのステートメントの後に発生します。)Py_DEBUG
によって暗示されます。
詳細については、PythonソースディストリビューションのMisc/SpecialBuilds.txt
を参照してください。