# 调用协议

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

## tp_call 协议

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

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

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

这个约定不仅被*tp_call*使用： `tp_new` 和 `tp_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()` 通常是最有效的。

備註

在 CPython 3.8 中，vectorcall API 和相关的函数暂定以带开头下划线的名称提供: `_PyObject_Vectorcall`, `_Py_TPFLAGS_HAVE_VECTORCALL`, `_PyObject_VectorcallMethod`, `_PyVectorcall_Function`, `_PyObject_CallOneArg`, `_PyObject_CallMethodNoArgs`, `_PyObject_CallMethodOneArg`。 此外， `PyObject_VectorcallDict` 以 `_PyObject_FastCallDict` 的名称提供。 旧名称仍然被定义为不带下划线的新名称的别名。

### 递归控制

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

为保证效率，这不适用于使用 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` 函数以便将来扩展。

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

  3.8 版新加入.

vectorcallfunc `PyVectorcall_Function`(PyObject *op)

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

  这在检查 op 是否支持 vectorcall 时最有用处，可以通过检查 `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` 。这个函数不会调用失败。