呼び出しプロトコル—Pythonドキュメント

提供:Dev Guides
< PythonPython/docs/3.9/c-api/call
移動先:案内検索

呼び出しプロトコル

CPythonは、 tp_call とvectorcallの2つの異なる呼び出しプロトコルをサポートしています。

tp_call プロトコル

tp_call を設定するクラスのインスタンスは呼び出し可能です。 スロットの署名は次のとおりです。

PyObject *tp_call(PyObject *callable, PyObject *args, PyObject *kwargs);

Pythonコードのcallable(*args, **kwargs)と同様に、位置引数にタプルを使用し、キーワード引数にdictを使用して呼び出しが行われます。 args はNULL以外である必要があります(引数がない場合は空のタプルを使用します)が、キーワード引数がない場合は kwargsNULL である可能性があります。

この規則は、 tp_call によって使用されるだけでなく、 tp_new および tp_init もこの方法で引数を渡します。

オブジェクトを呼び出すには、 PyObject_Call()または他の呼び出しAPI を使用します。


Vectorcallプロトコル

バージョン3.9の新機能。


vectorcallプロトコルは、呼び出しをより効率的にするための追加プロトコルとして PEP 590 で導入されました。

経験則として、CPythonは、callableがそれをサポートしている場合、内部呼び出しにvectorcallを優先します。 ただし、これは難しいルールではありません。 さらに、一部のサードパーティ拡張機能は、( PyObject_Call()を使用するのではなく) tp_call を直接使用します。 したがって、vectorcallをサポートするクラスは、 tp_call も実装する必要があります。 さらに、呼び出し可能オブジェクトは、使用されるプロトコルに関係なく同じように動作する必要があります。 これを実現するための推奨される方法は、 tp_callPyVectorcall_Call()に設定することです。 これは繰り返しになります:

警告

vectorcall must をサポートするクラスも、同じセマンティクスで tp_call を実装します。


tp_call よりも遅い場合、クラスはvectorcallを実装しないでください。 たとえば、呼び出し先が引数をargsタプルに変換する必要があり、とにかくkwargs dictを使用する場合、vectorcallを実装しても意味がありません。

クラスは、 Py_TPFLAGS_HAVE_VECTORCALL フラグを有効にし、 tp_vectorcall_offsetvectorcallfunc が表示されるオブジェクト構造内のオフセットに設定することでvectorcallプロトコルを実装できます。 これは、次のシグネチャを持つ関数へのポインタです。

typedef PyObject *(*vectorcallfunc)(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames)
  • callable は、呼び出されるオブジェクトです。
  • *; args は、位置引数とそれに続く
    キーワード引数の値。 引数がない場合、これは NULL になる可能性があります。
  • *; nargsf は、位置引数の数に、場合によっては
    PY_VECTORCALL_ARGUMENTS_OFFSETフラグ。 nargsf から位置引数の実際の数を取得するには、 PyVectorcall_NARGS()を使用します。
  • *; kwnames は、キーワード引数の名前を含むタプルです。
    言い換えれば、kwargsのキーが口述します。 これらの名前は文字列(strまたはサブクラスのインスタンス)である必要があり、一意である必要があります。 キーワード引数がない場合は、代わりに kwnamesNULL にすることができます。
PY_VECTORCALL_ARGUMENTS_OFFSET

このフラグがvectorcall nargsf 引数に設定されている場合、呼び出し先はargs[-1]を一時的に変更できます。 言い換えると、 args は、割り当てられたベクトルの引数1(0ではない)を指します。 呼び出し先は、戻る前にargs[-1]の値を復元する必要があります。

PyObject_VectorcallMethod()の場合、このフラグは、代わりにargs[0]が変更される可能性があることを意味します。

(追加の割り当てなしで)安価に実行できる場合は常に、発信者はPY_VECTORCALL_ARGUMENTS_OFFSETを使用することをお勧めします。 そうすることで、バインドされたメソッドなどの呼び出し可能オブジェクトが、後続の呼び出し(先頭に self 引数を含む)を非常に効率的に行うことができます。

vectorcallを実装するオブジェクトを呼び出すには、他の呼び出し可能オブジェクトと同様に、 call API 関数を使用します。 PyObject_Vectorcall()は通常最も効率的です。

ノート

CPython 3.8では、vectorcall APIおよび関連する関数は、先頭にアンダースコアが付いた名前で暫定的に使用可能でした:_PyObject_Vectorcall_Py_TPFLAGS_HAVE_VECTORCALL_PyObject_VectorcallMethod_PyVectorcall_Function、[X169X ] 、_PyObject_CallMethodNoArgs_PyObject_CallMethodOneArg。 さらに、PyObject_VectorcallDict_PyObject_FastCallDictとして利用可能でした。 古い名前は、下線が引かれていない新しい名前のエイリアスとして引き続き定義されます。


再帰制御

tp_call を使用する場合、呼び出し先は再帰について心配する必要はありません。CPythonは Py_EnterRecursiveCall()および Py_LeaveRecursiveCall()を使用して行われた呼び出しに使用します。 tp_call

効率を上げるために、これはvectorcallを使用して行われる呼び出しには当てはまりません。呼び出し先は、必要に応じて Py_EnterRecursiveCall および Py_LeaveRecursiveCall を使用する必要があります。


VectorcallサポートAPI

Py_ssize_t PyVectorcall_NARGS(size_t nargsf)

vectorcall nargsf 引数が与えられた場合、引数の実際の数を返します。 現在、次のものと同等です。

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)

ただし、将来の拡張を可能にするために、関数PyVectorcall_NARGSを使用する必要があります。

この関数は、制限付きAPI の一部ではありません。

バージョン3.8の新機能。

vectorcallfunc PyVectorcall_Function(PyObject *op)

op がvectorcallプロトコルをサポートしていない場合(型がサポートしていないか、特定のインスタンスがサポートしていないため)、 NULL を返します。 それ以外の場合は、 op に格納されているvectorcall関数ポインタを返します。 この関数で例外が発生することはありません。

これは、 op がvectorcallをサポートしているかどうかを確認するのに最も役立ちます。これは、PyVectorcall_Function(op) != NULLを確認することで実行できます。

この関数は、制限付きAPI の一部ではありません。

バージョン3.8の新機能。

PyObject *PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *dict)

callablevectorcallfunc を、それぞれタプルとdictで指定された位置引数とキーワード引数を使用して呼び出します。

これは、 tp_call スロットに配置するか、tp_callの実装で使用することを目的とした特殊な関数です。 Py_TPFLAGS_HAVE_VECTORCALL フラグをチェックせず、tp_callにフォールバックしません。

この関数は、制限付きAPI の一部ではありません。

バージョン3.8の新機能。


オブジェクト呼び出しAPI

Pythonオブジェクトを呼び出すために、さまざまな関数を使用できます。 それぞれが引数を、呼び出されたオブジェクトでサポートされている規則( tp_call またはvectorcall)に変換します。 変換をできるだけ少なくするために、利用可能なデータの形式に最適なものを選択してください。

次の表は、使用可能な機能をまとめたものです。 詳細については、個々のドキュメントを参照してください。

関数 呼び出し可能 引数 kwargs
PyObject_Call() PyObject * タプル dict / NULL
PyObject_CallNoArgs() PyObject *
PyObject_CallOneArg() PyObject * 1つのオブジェクト
PyObject_CallObject() PyObject * タプル/ NULL
PyObject_CallFunction() PyObject * フォーマット
PyObject_CallMethod() obj + char* フォーマット
PyObject_CallFunctionObjArgs() PyObject * 可変個引数
PyObject_CallMethodObjArgs() obj +名前 可変個引数
PyObject_CallMethodNoArgs() obj +名前
PyObject_CallMethodOneArg() obj +名前 1つのオブジェクト
PyObject_Vectorcall() PyObject * vectorcall vectorcall
PyObject_VectorcallDict() PyObject * vectorcall dict / NULL
PyObject_VectorcallMethod() arg +名前 vectorcall vectorcall
PyObject *PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)

タプル args によって指定された引数と、ディクショナリ kwargs によって指定された名前付き引数を使用して、呼び出し可能なPythonオブジェクト callable を呼び出します。

argsNULL であってはなりません。 引数が必要ない場合は、空のタプルを使用します。 名前付き引数が必要ない場合、 kwargsNULL にすることができます。

成功した場合は呼び出しの結果を返すか、例外を発生させて失敗した場合は NULL を返します。

これは、Python式callable(*args, **kwargs)と同等です。

PyObject *PyObject_CallNoArgs(PyObject *callable)

引数なしで呼び出し可能なPythonオブジェクト callable を呼び出します。 これは、引数なしで呼び出し可能なPythonオブジェクトを呼び出すための最も効率的な方法です。

成功した場合は呼び出しの結果を返すか、例外を発生させて失敗した場合は NULL を返します。

バージョン3.9の新機能。

PyObject *PyObject_CallOneArg(PyObject *callable, PyObject *arg)

呼び出し可能なPythonオブジェクト callable を、位置引数 arg を1つだけ使用し、キーワード引数なしで呼び出します。

成功した場合は呼び出しの結果を返すか、例外を発生させて失敗した場合は NULL を返します。

この関数は、制限付きAPI の一部ではありません。

バージョン3.9の新機能。

PyObject *PyObject_CallObject(PyObject *callable, PyObject *args)

タプル args で引数を指定して、呼び出し可能なPythonオブジェクト callable を呼び出します。 引数が必要ない場合、 argsNULL にすることができます。

成功した場合は呼び出しの結果を返すか、例外を発生させて失敗した場合は NULL を返します。

これは、Python式callable(*args)と同等です。

PyObject *PyObject_CallFunction(PyObject *callable, const char *format, ...)

可変数のC引数を使用して、呼び出し可能なPythonオブジェクト callable を呼び出します。 C引数は、 Py_BuildValue()スタイルのフォーマット文字列を使用して記述されます。 形式は NULL にすることができ、引数が指定されていないことを示します。

成功した場合は呼び出しの結果を返すか、例外を発生させて失敗した場合は NULL を返します。

これは、Python式callable(*args)と同等です。

PyObject * 引数のみを渡す場合は、 PyObject_CallFunctionObjArgs()の方が高速です。

バージョン3.4で変更: フォーマットのタイプがchar *から変更されました。

PyObject *PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...)

オブジェクト objname という名前のメソッドを、可変数のC引数を使用して呼び出します。 C引数は、タプルを生成する必要がある Py_BuildValue()形式の文字列によって記述されます。

形式は NULL にすることができ、引数が指定されていないことを示します。

成功した場合は呼び出しの結果を返すか、例外を発生させて失敗した場合は NULL を返します。

これは、Python式obj.name(arg1, arg2, ...)と同等です。

PyObject * 引数のみを渡す場合は、 PyObject_CallMethodObjArgs()の方が高速な代替手段であることに注意してください。

バージョン3.4で変更: name および format のタイプがchar *から変更されました。

PyObject *PyObject_CallFunctionObjArgs(PyObject *callable, ...)

可変数の PyObject * 引数を使用して、呼び出し可能なPythonオブジェクト callable を呼び出します。 引数は、 NULL が後に続く可変数のパラメーターとして提供されます。

成功した場合は呼び出しの結果を返すか、例外を発生させて失敗した場合は NULL を返します。

これは、Python式callable(arg1, arg2, ...)と同等です。

PyObject *PyObject_CallMethodObjArgs(PyObject *obj, PyObject *name, ...)

Pythonオブジェクト obj のメソッドを呼び出します。ここで、メソッドの名前は name のPython文字列オブジェクトとして指定されます。 これは、可変数の PyObject * 引数で呼び出されます。 引数は、 NULL が後に続く可変数のパラメーターとして提供されます。

成功した場合は呼び出しの結果を返すか、例外を発生させて失敗した場合は NULL を返します。

PyObject *PyObject_CallMethodNoArgs(PyObject *obj, PyObject *name)

Pythonオブジェクト obj のメソッドを引数なしで呼び出します。ここで、メソッドの名前は name のPython文字列オブジェクトとして指定されます。

成功した場合は呼び出しの結果を返すか、例外を発生させて失敗した場合は NULL を返します。

この関数は、制限付きAPI の一部ではありません。

バージョン3.9の新機能。

PyObject *PyObject_CallMethodOneArg(PyObject *obj, PyObject *name, PyObject *arg)

Pythonオブジェクト obj のメソッドを単一の位置引数 arg で呼び出します。ここで、メソッドの名前は name のPython文字列オブジェクトとして指定されます。

成功した場合は呼び出しの結果を返すか、例外を発生させて失敗した場合は NULL を返します。

この関数は、制限付きAPI の一部ではありません。

バージョン3.9の新機能。

PyObject *PyObject_Vectorcall(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames)

呼び出し可能なPythonオブジェクト callable を呼び出します。 引数は vectorcallfunc の場合と同じです。 callablevectorcall をサポートしている場合、これは callable に格納されているvectorcall関数を直接呼び出します。

成功した場合は呼び出しの結果を返すか、例外を発生させて失敗した場合は NULL を返します。

この関数は、制限付きAPI の一部ではありません。

バージョン3.9の新機能。

PyObject *PyObject_VectorcallDict(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwdict)

vectorcall プロトコルとまったく同じように位置引数を渡し、キーワード引数を辞書 kwdict として渡して、 callable を呼び出します。 args 配列には、位置引数のみが含まれています。

内部で使用されるプロトコルに関係なく、引数の変換を行う必要があります。 したがって、この関数は、呼び出し元がキーワード引数に使用する準備ができている辞書をすでに持っている場合にのみ使用する必要がありますが、位置引数のタプルは使用しないでください。

この関数は、制限付きAPI の一部ではありません。

バージョン3.9の新機能。

PyObject *PyObject_VectorcallMethod(PyObject *name, PyObject *const *args, size_t nargsf, PyObject *kwnames)

vectorcall呼び出し規約を使用してメソッドを呼び出します。 メソッドの名前は、Python文字列 name として指定されます。 メソッドが呼び出されるオブジェクトは args [0] であり、 args [1] で始まる args 配列は呼び出しの引数を表します。 少なくとも1つの位置引数が必要です。 nargsf は、 args [0] に加えて、args[0]の値が一時的に変更される可能性がある場合はPY_VECTORCALL_ARGUMENTS_OFFSETを含む位置引数の数です。 キーワード引数は、 PyObject_Vectorcall()と同じように渡すことができます。

オブジェクトに Py_TPFLAGS_METHOD_DESCRIPTOR 機能がある場合、これは完全な args ベクトルを引数として持つ非バインドメソッドオブジェクトを呼び出します。

成功した場合は呼び出しの結果を返すか、例外を発生させて失敗した場合は NULL を返します。

この関数は、制限付きAPI の一部ではありません。

バージョン3.9の新機能。


サポートAPIを呼び出す

int PyCallable_Check(PyObject *o)
オブジェクト o が呼び出し可能かどうかを判別します。 オブジェクトが呼び出し可能である場合は1を返し、そうでない場合は0を返します。 この関数は常に成功します。