调用协议

CPython 支持两种不同的调用协议:tp_call 和矢量调用。

tp_call 协议

设置 tp_call 的类的实例都是可调用的。 槽位的签名为:

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

一个调用是用一个元组表示位置参数,用一个dict表示关键字参数,类似于Python代码中的``callable(args, \*kwargs)``。*args*必须是非空的(如果没有参数,会使用一个空元组),但如果没有关键字参数,*kwargs*可以是*NULL*。

这个约定不仅被*tp_call*使用: tp_newtp_init 也这样传递参数。

使用 PyObject_Call() 或其他 调用 API 来调用一个对象。

Vectorcall 协议

3.9 新版功能.

vectorcall 协议是在 PEP 590 被引入的,它是使调用函数更加有效的附加协议。

作为经验法则,如果可调用程序支持 vectorcall,CPython 会更倾向于内联调用。 然而,这并不是一个硬性规定。 此外,一些第三方扩展直接使用 tp_call (而不是使用 PyObject_Call())。 因此,一个支持 vectorcall 的类也必须实现 tp_call。 此外,无论使用哪种协议,可调对象的行为都必须是相同的。 推荐的方法是将 tp_call 设置为 PyVectorcall_Call()。值得一提的是:

警告

一个支持 Vectorcall 的类 必须 也实现具有相同语义的 tp_call

如果一个类的vectorcall比*tp_call*慢,就不应该实现vectorcall。例如,如果被调用者需要将参数转换为args 元组和kwargs dict,那么实现vectorcall就没有意义。

类可以通过启用 Py_TPFLAGS_HAVE_VECTORCALL 标志并将 tp_vectorcall_offset 设置为对象结构中的 vectorcallfunc 的 offset 来实现 vectorcall 协议。这是一个指向具有以下签名的函数的指针:

PyObject *(*vectorcallfunc)(PyObject \callable, PyObject \const \args, size_t nargsf, PyObject *kwnames*)

  • callable 是指被调用的对象。

  • args 是一个C语言数组,由位置参数和后面的

    关键字参数的值。如果没有参数,这个值可以是 NULL

  • nargsf 是位置参数的数量加上可能的

    PY_VECTORCALL_ARGUMENTS_OFFSET 标志。 要从 nargsf 获得实际的位置参数数,请使用 PyVectorcall_NARGS()

  • kwnames 是一包含所有关键字名称的元组。

    换句话说,就是 kwargs 字典的键。 这些名字必须是字符串 (str 或其子类的实例),并且它们必须是唯一的。 如果没有关键字参数,那么 kwnames 可以用 NULL 代替。

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() 通常是最有效的。

注解

In CPython 3.8, the vectorcall API and related functions were available provisionally under names with a leading underscore: _PyObject_Vectorcall, _Py_TPFLAGS_HAVE_VECTORCALL, _PyObject_VectorcallMethod, _PyVectorcall_Function, _PyObject_CallOneArg, _PyObject_CallMethodNoArgs, _PyObject_CallMethodOneArg. Additionally, PyObject_VectorcallDict was available as _PyObject_FastCallDict. The old names are still defined as aliases of the new, non-underscored names.

递归控制

在使用 tp_call 时,被调用者不必担心 递归: CPython 对于使用 tp_call 进行的调用会使用 Py_EnterRecursiveCall()Py_LeaveRecursiveCall()

For efficiency, this is not the case for calls done using vectorcall: the callee should use Py_EnterRecursiveCall and Py_LeaveRecursiveCall if needed.

Vectorcall 支持 API

Py_ssize_t PyVectorcall_NARGS(size_t nargsf)

给定一个 vectorcall nargsf 实参,返回参数的实际数量。 目前等同于:

  1. (Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)

然而,应使用 PyVectorcall_NARGS 函数以便将来扩展。

这个函数不是 limited API 的一部分。

3.8 新版功能.

vectorcallfunc PyVectorcall_Function(PyObject \op*)

如果*op*不支持vectorcall协议(要么是因为类型不支持,要么是因为具体实例不支持),返回*NULL*。否则,返回存储在*op*中的vectorcall函数指针。这个函数从不触发异常。

This is mostly useful to check whether or not op supports vectorcall, which can be done by checking PyVectorcall_Function(op) != NULL.

这个函数不是 limited API 的一部分。

3.8 新版功能.

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

调用*可调对象*的 vectorcallfunc,其位置参数和关键字参数分别以元组和dict形式给出。

This is a specialized function, intended to be put in the tp_call slot or be used in an implementation of tp_call. It does not check the Py_TPFLAGS_HAVE_VECTORCALL flag and it does not fall back to tp_call.

这个函数不是 limited API 的一部分。

3.8 新版功能.

调用对象的 API

Various functions are available for calling a Python object. Each converts its arguments to a convention supported by the called object – either tp_call or vectorcall. In order to do as litle conversion as possible, pick one that best fits the format of data you have available.

下表总结了可用的功能; 请参阅各个文档以了解详细信息。

函数

可调用对象(Callable)

args

kwargs

PyObject_Call()

PyObject

元组

dict/NULL

PyObject_CallNoArgs()

PyObject

—-

—-

PyObject_CallOneArg()

PyObject

1个对象

—-

PyObject_CallObject()

PyObject

元组/NULL

—-

PyObject_CallFunction()

PyObject

format

—-

PyObject_CallMethod()

对象 + char

format

—-

PyObject_CallFunctionObjArgs()

PyObject

可变参数

—-

PyObject_CallMethodObjArgs()

对象 + 名称

可变参数

—-

PyObject_CallMethodNoArgs()

对象 + 名称

—-

—-

PyObject_CallMethodOneArg()

对象 + 名称

1个对象

—-

PyObject_Vectorcall()

PyObject

vectorcall

vectorcall

PyObject_VectorcallDict()

PyObject *

vectorcall

dict/NULL

PyObject_VectorcallMethod()

参数 + 名称

vectorcall

vectorcall

PyObject* PyObject_Call(PyObject \callable, PyObject *args, PyObject *kwargs*)

Return value: New reference.

Call a callable Python object callable, with arguments given by the tuple args, and named arguments given by the dictionary kwargs.

args must not be NULL; use an empty tuple if no arguments are needed. If no named arguments are needed, kwargs can be NULL.

成功时返回结果,在失败时抛出一个异常并返回 NULL

这等价于 Python 表达式 callable(*args, **kwargs)

PyObject* PyObject_CallNoArgs(PyObject \callable*)

Call a callable Python object callable without any arguments. It is the most efficient way to call a callable Python object without any argument.

成功时返回结果,在失败时抛出一个异常并返回 NULL

3.9 新版功能.

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

Call a callable Python object callable with exactly 1 positional argument arg and no keyword arguments.

成功时返回结果,在失败时抛出一个异常并返回 NULL

这个函数不是 limited API 的一部分。

3.9 新版功能.

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

Return value: New reference.

Call a callable Python object callable, with arguments given by the tuple args. If no arguments are needed, then args can be NULL.

成功时返回结果,在失败时抛出一个异常并返回 NULL

这等价于 Python 表达式 callable(*args)

PyObject* PyObject_CallFunction(PyObject \callable, const char *format*, …)

Return value: New reference.

Call a callable Python object callable, with a variable number of C arguments. The C arguments are described using a Py_BuildValue() style format string. The format can be NULL, indicating that no arguments are provided.

成功时返回结果,在失败时抛出一个异常并返回 NULL

这等价于 Python 表达式 callable(*args)

Note that if you only pass PyObject * args, PyObject_CallFunctionObjArgs() is a faster alternative.

在 3.4 版更改: 这个 format 类型已从 char * 更改。

PyObject* PyObject_CallMethod(PyObject \obj, const char *name, const char *format*, …)

Return value: New reference.

Call the method named name of object obj with a variable number of C arguments. The C arguments are described by a Py_BuildValue() format string that should produce a tuple.

格式可以为 NULL ,表示未提供任何参数。

成功时返回结果,在失败时抛出一个异常并返回 NULL

这和Python表达式``obj.name(arg1, arg2, …)``是一样的。

Note that if you only pass PyObject * args, PyObject_CallMethodObjArgs() is a faster alternative.

在 3.4 版更改: The types of name and format were changed from char *.

PyObject* PyObject_CallFunctionObjArgs(PyObject \callable*, …)

Return value: New reference.

Call a callable Python object callable, with a variable number of PyObject * arguments. The arguments are provided as a variable number of parameters followed by NULL.

成功时返回结果,在失败时抛出一个异常并返回 NULL

这和Python表达式``callable(arg1, arg2, …)``是一样的。

PyObject* PyObject_CallMethodObjArgs(PyObject \obj, PyObject *name*, …)

Return value: New reference.

Call a method of the Python object obj, where the name of the method is given as a Python string object in name. It is called with a variable number of PyObject * arguments. The arguments are provided as a variable number of parameters followed by NULL.

成功时返回结果,在失败时抛出一个异常并返回 NULL

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

Call a method of the Python object obj without arguments, where the name of the method is given as a Python string object in name.

成功时返回结果,在失败时抛出一个异常并返回 NULL

这个函数不是 limited API 的一部分。

3.9 新版功能.

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

Call a method of the Python object obj with a single positional argument arg, where the name of the method is given as a Python string object in name.

成功时返回结果,在失败时抛出一个异常并返回 NULL

这个函数不是 limited API 的一部分。

3.9 新版功能.

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

Call a callable Python object callable. The arguments are the same as for vectorcallfunc. If callable supports vectorcall, this directly calls the vectorcall function stored in callable.

成功时返回结果,在失败时抛出一个异常并返回 NULL

这个函数不是 limited API 的一部分。

3.9 新版功能.

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

Call callable with positional arguments passed exactly as in the vectorcall protocol, but with keyword arguments passed as a dictionary kwdict. The args array contains only the positional arguments.

Regardless of which protocol is used internally, a conversion of arguments needs to be done. Therefore, this function should only be used if the caller already has a dictionary ready to use for the keyword arguments, but not a tuple for the positional arguments.

这个函数不是 limited API 的一部分。

3.9 新版功能.

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

Call a method using the vectorcall calling convention. The name of the method is given as a Python string name. The object whose method is called is args[0], and the args array starting at args[1] represents the arguments of the call. There must be at least one positional argument. nargsf is the number of positional arguments including args[0], plus PY_VECTORCALL_ARGUMENTS_OFFSET if the value of args[0] may temporarily be changed. Keyword arguments can be passed just like in PyObject_Vectorcall().

If the object has the Py_TPFLAGS_METHOD_DESCRIPTOR feature, this will call the unbound method object with the full args vector as arguments.

成功时返回结果,在失败时抛出一个异常并返回 NULL

这个函数不是 limited API 的一部分。

3.9 新版功能.

调用支持 API

int PyCallable_Check(PyObject \o*)

确定对象 o 是可调对象。如果对象是可调对象则返回 1 ,其他情况返回 0 。这个函数不会调用失败。