呼叫协议¶
CPython支持两种不同的调用协议: tp_call 还有矢量呼叫。
这个 tp_call 协议¶
类的实例 tp_call 是可以调用的。插槽的签名是:
PyObject *tp_call(PyObject *callable, PyObject *args, PyObject *kwargs);
调用时,位置参数使用元组,关键字参数使用dict,类似于 callable(*args, **kwargs) 在Python代码中。 args 必须为非空(如果没有参数,请使用空元组),但是 关键字参数 可能是 NULL 如果没有关键字参数。
本公约不仅由 tp_call : tp_new 和 tp_init 也可以这样传递参数。
要调用对象,请使用 PyObject_Call() 或其他 call API .
矢量调用协议¶
3.9 新版功能.
矢量调用协议在 PEP 590 作为提高通话效率的附加协议。
根据经验,如果可调用函数支持的话,CPython更喜欢内部调用的vectorcall。然而,这并不是一条硬性规定。另外,一些第三方扩展使用 tp_call 直接(而不是使用 PyObject_Call() ). 因此,支持vectorcall的类也必须实现 tp_call . 此外,无论使用哪种协议,可调用的行为都必须相同。建议通过设置 tp_call 到 PyVectorcall_Call() . 这需要重复:
警告
支持向量调用的类 must 同时执行 tp_call 具有相同的语义。
如果一个类实现vectorcall的速度低于 tp_call . 例如,如果被调用方无论如何都需要将参数转换为args元组和kwargs dict,那么实现vectorcall就没有意义。
类可以通过启用 Py_TPFLAGS_HAVE_VECTORCALL 标志和设置 tp_vectorcall_offset 到对象结构内部的偏移,其中 矢量调用函数 出现。这是指向具有以下签名的函数的指针:
-
typedef PyObject *(*vectorcallfunc)(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames)¶
可赎回的 是被调用的对象。
- args 是一个C数组,由位置参数后跟
关键字参数的值。这可能是 NULL 如果没有参数。
- 纳尔斯夫 位置参数的数目加上
PY_VECTORCALL_ARGUMENTS_OFFSET旗帜。从中获取位置参数的实际数目 纳尔斯夫 使用PyVectorcall_NARGS().
- KW名称 是包含关键字参数名称的元组;
换句话说,kwargs dict的键。这些名称必须是字符串(例如
str或者一个子类),它们必须是唯一的。如果没有关键字参数,则 KW名称 可以改为 NULL .
-
PY_VECTORCALL_ARGUMENTS_OFFSET¶
如果在矢量调用中设置了此标志 纳尔斯夫 参数,允许被调用方临时更改
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 ,被叫方不必担心 recursion :CPython使用 Py_EnterRecursiveCall() 和 Py_LeaveRecursiveCall() 对于使用 tp_call .
为了提高效率,使用vectorcall完成的调用不是这样的:被调用方应该使用 Py_EnterRecursiveCall 和 Py_LeaveRecursiveCall 如果需要的话。
矢量调用支持API¶
-
Py_ssize_t PyVectorcall_NARGS(size_t nargsf)¶
给了一个vectorcall 纳尔斯夫 参数,返回参数的实际数目。目前相当于:
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
但是,功能
PyVectorcall_NARGS应用于考虑将来的扩展。此函数不是 limited API .
3.8 新版功能.
-
vectorcallfunc PyVectorcall_Function(PyObject *op)¶
如果 op 不支持vectorcall协议(因为类型不支持或因为特定实例不支持),返回 NULL . 否则,返回存储在 op . 此函数从不引发异常。
这对于检查是否 op 支持向量调用,可以通过检查
PyVectorcall_Function(op) != NULL.此函数不是 limited API .
3.8 新版功能.
-
PyObject *PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *dict)¶
呼叫 可赎回的 的
vectorcallfunc在元组和dict中分别给出位置参数和关键字参数。这是一个专门的函数,旨在将
tp_call插槽或用于tp_call. 它不会检查Py_TPFLAGS_HAVE_VECTORCALL旗,它不会落回tp_call.此函数不是 limited API .
3.8 新版功能.
对象调用API¶
可以使用各种函数调用Python对象。每个参数都将其参数转换为被调用对象支持的约定-或者 tp_call 或矢量调用。为了尽可能地进行简单的转换,请选择最适合可用数据格式的转换。
下表总结了可用的功能;有关详细信息,请参阅各个文档。
功能 |
可赎回的 |
阿尔茨海默病 |
关键字参数 |
|---|---|---|---|
|
元组 |
dict/ |
|
|
--- |
--- |
|
|
1个对象 |
--- |
|
|
元组/ |
--- |
|
|
格式 |
--- |
|
目标+ |
格式 |
--- |
|
|
可变的 |
--- |
|
对象+名称 |
可变的 |
--- |
|
对象+名称 |
--- |
--- |
|
对象+名称 |
1个对象 |
--- |
|
|
矢量呼叫 |
矢量呼叫 |
|
|
矢量呼叫 |
dict/ |
|
arg+名称 |
矢量呼叫 |
矢量呼叫 |
-
PyObject *PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)¶
- Return value: New reference.
调用可调用的python对象 可赎回的 ,由元组提供参数 args 和字典给出的命名参数 关键字参数 .
args 不得 NULL ;如果不需要参数,则使用空元组。如果不需要命名参数, 关键字参数 可以是 NULL .
返回成功调用的结果,或引发异常并返回 NULL 失败论。
这相当于python表达式:
callable(*args, **kwargs).
-
PyObject *PyObject_CallNoArgs(PyObject *callable)¶
调用可调用的python对象 可赎回的 没有任何参数。它是调用不带任何参数的可调用Python对象的最有效方法。
返回成功调用的结果,或引发异常并返回 NULL 失败论。
3.9 新版功能.
-
PyObject *PyObject_CallOneArg(PyObject *callable, PyObject *arg)¶
调用可调用的python对象 可赎回的 只有一个位置参数 arg 没有关键字参数。
返回成功调用的结果,或引发异常并返回 NULL 失败论。
此函数不是 limited API .
3.9 新版功能.
-
PyObject *PyObject_CallObject(PyObject *callable, PyObject *args)¶
- Return value: New reference.
调用可调用的python对象 可赎回的 ,由元组提供参数 args . 如果不需要参数,那么 args 可以是 NULL .
返回成功调用的结果,或引发异常并返回 NULL 失败论。
这相当于python表达式:
callable(*args).
-
PyObject *PyObject_CallFunction(PyObject *callable, const char *format, ...)¶
- Return value: New reference.
调用可调用的python对象 可赎回的 ,参数个数可变。C参数用
Py_BuildValue()样式格式字符串。格式可以是 NULL ,指示未提供参数。返回成功调用的结果,或引发异常并返回 NULL 失败论。
这相当于python表达式:
callable(*args).注意,如果你只通过 PyObject* ARGS,
PyObject_CallFunctionObjArgs()是一个更快的选择。在 3.4 版更改: 的类型 格式 已从更改
char *.
-
PyObject *PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...)¶
- Return value: New reference.
调用名为的方法 name 对象的 obj 带有可变数量的C参数。c参数由a描述
Py_BuildValue()应生成元组的格式字符串。格式可以是 NULL ,指示未提供参数。
返回成功调用的结果,或引发异常并返回 NULL 失败论。
这相当于python表达式:
obj.name(arg1, arg2, ...).注意,如果你只通过 PyObject* ARGS,
PyObject_CallMethodObjArgs()是一个更快的选择。在 3.4 版更改: 类型 name 和 格式 已从更改
char *.
-
PyObject *PyObject_CallFunctionObjArgs(PyObject *callable, ...)¶
- Return value: New reference.
调用可调用的python对象 可赎回的 ,变量为 PyObject* 参数。参数以参数的可变数目提供,后跟 NULL .
返回成功调用的结果,或引发异常并返回 NULL 失败论。
这相当于python表达式:
callable(arg1, arg2, ...).
-
PyObject *PyObject_CallMethodObjArgs(PyObject *obj, PyObject *name, ...)¶
- Return value: New reference.
调用python对象的方法 obj ,其中方法的名称作为python字符串对象提供 name . 它的调用变量为 PyObject* 参数。参数以参数的可变数目提供,后跟 NULL .
返回成功调用的结果,或引发异常并返回 NULL 失败论。
-
PyObject *PyObject_CallMethodNoArgs(PyObject *obj, PyObject *name)¶
调用python对象的方法 obj 不带参数,其中方法的名称作为中的python字符串对象提供 name .
返回成功调用的结果,或引发异常并返回 NULL 失败论。
此函数不是 limited API .
3.9 新版功能.
-
PyObject *PyObject_CallMethodOneArg(PyObject *obj, PyObject *name, PyObject *arg)¶
调用python对象的方法 obj 只有一个位置参数 arg ,其中方法的名称作为python字符串对象提供 name .
返回成功调用的结果,或引发异常并返回 NULL 失败论。
此函数不是 limited API .
3.9 新版功能.
-
PyObject *PyObject_Vectorcall(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames)¶
调用可调用的python对象 可赎回的 . 这些论点与
vectorcallfunc.如果 可赎回的 支架 vectorcall, 它直接调用存储在 可赎回的 .返回成功调用的结果,或引发异常并返回 NULL 失败论。
此函数不是 limited API .
3.9 新版功能.
-
PyObject *PyObject_VectorcallDict(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwdict)¶
呼叫 可赎回的 传递的位置参数与 vectorcall 协议,但关键字参数作为字典传递 克威特 . 这个 args 数组只包含位置参数。
无论在内部使用哪种协议,都需要进行参数转换。因此,仅当调用方已准备好用于关键字参数的字典,而不是用于位置参数的元组时,才应使用此函数。
此函数不是 limited API .
3.9 新版功能.
-
PyObject *PyObject_VectorcallMethod(PyObject *name, PyObject *const *args, size_t nargsf, PyObject *kwnames)¶
使用vectorcall调用约定调用方法。方法的名称以Python字符串的形式给出 name . 调用方法的对象是 [参数[0]] 和 args 数组开始于 [参数[1]] 表示调用的参数。必须至少有一个位置参数。 纳尔斯夫 是位置参数的数目,包括 [参数[0]] 加上
PY_VECTORCALL_ARGUMENTS_OFFSET如果值args[0]可临时更改。关键字参数的传递方式与PyObject_Vectorcall().如果对象具有
Py_TPFLAGS_METHOD_DESCRIPTOR功能,这将调用 args 矢量作为参数。返回成功调用的结果,或引发异常并返回 NULL 失败论。
此函数不是 limited API .
3.9 新版功能.