> **Источник:** https://python-all.ru/3.13/c-api/call.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# Протокол вызова

CPython поддерживает два протокола вызова: *tp\_call* и vectorcall.

## *tp\_call*

Экземпляры классов, в которых задан [`tp_call`](https://python-all.ru/3.13/c-api/typeobj.html#c.PyTypeObject.tp_call), являются вызываемыми. Сигнатура слота:

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

Вызов производится с использованием кортежа для позиционных аргументов и словаря для именованных аргументов, аналогично `callable(*args, **kwargs)` в коде Python. *args* должно быть не NULL (используйте пустой кортеж, если аргументов нет), но *kwargs* может быть *NULL*, если именованные аргументы отсутствуют.

Это соглашение используется не только в *tp\_call*: [`tp_new`](https://python-all.ru/3.13/c-api/typeobj.html#c.PyTypeObject.tp_new) и [`tp_init`](https://python-all.ru/3.13/c-api/typeobj.html#c.PyTypeObject.tp_init) также передают аргументы таким образом.

Для вызова объекта используйте [`PyObject_Call()`](https://python-all.ru/3.13/c-api/call.html#c.PyObject_Call) или другой [API вызова](https://python-all.ru/3.13/c-api/call.html#capi-call).

## Протокол Vectorcall

Добавлено в версии 3.9.

Протокол vectorcall был представлен в [**PEP 590**](https://python-all.ru/3.13/c-api/call.html) как дополнительный протокол для повышения эффективности вызовов.

Как правило, CPython предпочитает vectorcall для внутренних вызовов, если вызываемый объект его поддерживает. Однако это не жёсткое правило. Кроме того, некоторые сторонние расширения используют *tp\_call* напрямую (вместо [`PyObject_Call()`](https://python-all.ru/3.13/c-api/call.html#c.PyObject_Call)). Поэтому класс, поддерживающий vectorcall, должен также реализовывать [`tp_call`](https://python-all.ru/3.13/c-api/typeobj.html#c.PyTypeObject.tp_call). Более того, вызываемый объект должен вести себя одинаково независимо от используемого протокола. Рекомендуемый способ добиться этого – задать `tp_call` равным [`PyVectorcall_Call()`](https://python-all.ru/3.13/c-api/call.html#c.PyVectorcall_Call). Это стоит повторить:

> **Предупреждение**
>
> Класс, поддерживающий vectorcall, **должен** также реализовывать [`tp_call`](https://python-all.ru/3.13/c-api/typeobj.html#c.PyTypeObject.tp_call) с той же семантикой.

Изменено в версии 3.12: Флаг [`Py_TPFLAGS_HAVE_VECTORCALL`](https://python-all.ru/3.13/c-api/typeobj.html#c.Py_TPFLAGS_HAVE_VECTORCALL) теперь удаляется из класса, когда метод [`__call__()`](https://python-all.ru/3.13/reference/datamodel.html#object.__call__) класса переопределяется. (При этом внутренне устанавливается только [`tp_call`](https://python-all.ru/3.13/c-api/typeobj.html#c.PyTypeObject.tp_call), что может привести к поведению, отличному от функции vectorcall). В более ранних версиях Python vectorcall следует использовать только с [`immutable`](https://python-all.ru/3.13/c-api/typeobj.html#c.Py_TPFLAGS_IMMUTABLETYPE) или статическими типами.

Класс не должен реализовывать vectorcall, если это будет медленнее, чем *tp\_call*. Например, если вызываемая сторона всё равно должна преобразовывать аргументы в кортеж args и словарь kwargs, то нет смысла реализовывать vectorcall.

Классы могут реализовать протокол vectorcall, установив флаг [`Py_TPFLAGS_HAVE_VECTORCALL`](https://python-all.ru/3.13/c-api/typeobj.html#c.Py_TPFLAGS_HAVE_VECTORCALL) и задав [`tp_vectorcall_offset`](https://python-all.ru/3.13/c-api/typeobj.html#c.PyTypeObject.tp_vectorcall_offset) в качестве смещения внутри структуры объекта, где находится *vectorcallfunc*. Это указатель на функцию со следующей сигнатурой:

#### `typedef PyObject *(*vectorcallfunc)(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames)`

*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable) начиная с версии 3.12.*

- *callable* – это вызываемый объект.
- ***args* – это массив C, состоящий из позиционных аргументов, за которыми следуют**

  значения именованных аргументов. Может быть *NULL*, если аргументов нет.
- ***nargsf* – это количество позиционных аргументов плюс, возможно,**

  флаг [`PY_VECTORCALL_ARGUMENTS_OFFSET`](https://python-all.ru/3.13/c-api/call.html#c.PY_VECTORCALL_ARGUMENTS_OFFSET). Чтобы получить фактическое количество позиционных аргументов из *nargsf*, используйте [`PyVectorcall_NARGS()`](https://python-all.ru/3.13/c-api/call.html#c.PyVectorcall_NARGS).
- ***kwnames* – это кортеж, содержащий имена именованных аргументов;**

  другими словами, ключи словаря kwargs. Эти имена должны быть строками (экземплярами `str` или подкласса) и они должны быть уникальными. Если именованных аргументов нет, то *kwnames* может быть *NULL*.

#### `PY_VECTORCALL_ARGUMENTS_OFFSET`

*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable) начиная с версии 3.12.*

Если этот флаг установлен в аргументе vectorcall *nargsf*, вызываемой стороне разрешается временно изменить `args[-1]`. Иными словами, *args* указывает на аргумент 1 (а не 0) в выделенном векторе. Вызываемая сторона должна восстановить значение `args[-1]` перед возвратом.

Для [`PyObject_VectorcallMethod()`](https://python-all.ru/3.13/c-api/call.html#c.PyObject_VectorcallMethod) этот флаг, напротив, означает, что `args[0]` может быть изменён.

Если это можно сделать дёшево (без дополнительных выделений памяти), вызывающим сторонам рекомендуется использовать [`PY_VECTORCALL_ARGUMENTS_OFFSET`](https://python-all.ru/3.13/c-api/call.html#c.PY_VECTORCALL_ARGUMENTS_OFFSET). Это позволит таким вызываемым объектам, как связанные методы, выполнять последующие вызовы (которые включают добавленный аргумент *self*) очень эффективно.

Добавлено в версии 3.8.

Для вызова объекта, реализующего vectorcall, используйте функцию [call API](https://python-all.ru/3.13/c-api/call.html#capi-call), как и для любого другого вызываемого объекта. Обычно наиболее эффективным будет [`PyObject_Vectorcall()`](https://python-all.ru/3.13/c-api/call.html#c.PyObject_Vectorcall).

### Управление рекурсией

При использовании *tp\_call* вызываемым сторонам не нужно беспокоиться о [рекурсии](https://python-all.ru/3.13/c-api/exceptions.html#recursion): CPython использует [`Py_EnterRecursiveCall()`](https://python-all.ru/3.13/c-api/exceptions.html#c.Py_EnterRecursiveCall) и [`Py_LeaveRecursiveCall()`](https://python-all.ru/3.13/c-api/exceptions.html#c.Py_LeaveRecursiveCall) для вызовов, выполненных с помощью *tp\_call*.

Для эффективности это не относится к вызовам, выполненным с помощью vectorcall: вызываемая сторона должна использовать *Py\_EnterRecursiveCall* и *Py\_LeaveRecursiveCall*, если это необходимо.

### API поддержки Vectorcall

#### `Py_ssize_t PyVectorcall_NARGS(size_t nargsf)`

*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable) начиная с версии 3.12.*

Получив аргумент vectorcall *nargsf*, возвращает фактическое количество аргументов. В настоящее время эквивалентно:

```c
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
```

Однако следует использовать функцию `PyVectorcall_NARGS`, чтобы обеспечить возможность будущих расширений.

Добавлено в версии 3.8.

#### `vectorcallfunc PyVectorcall_Function(PyObject *op)`

Если *op* не поддерживает протокол vectorcall (либо из-за того, что тип не поддерживает, либо конкретный экземпляр), возвращает *NULL*. В противном случае возвращает указатель на функцию vectorcall, сохранённый в *op*. Эта функция никогда не возбуждает исключения.

Это в основном полезно для проверки, поддерживает ли *op* vectorcall, что можно сделать, проверив `PyVectorcall_Function(op) != NULL`.

Добавлено в версии 3.9.

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

*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable) начиная с версии 3.12.*

Вызывает [`vectorcallfunc`](https://python-all.ru/3.13/c-api/call.html#c.vectorcallfunc) объекта *callable* с позиционными и именованными аргументами, заданными в виде кортежа и словаря соответственно.

Это специализированная функция, предназначенная для размещения в слоте [`tp_call`](https://python-all.ru/3.13/c-api/typeobj.html#c.PyTypeObject.tp_call) или использования в реализации `tp_call`. Она не проверяет флаг [`Py_TPFLAGS_HAVE_VECTORCALL`](https://python-all.ru/3.13/c-api/typeobj.html#c.Py_TPFLAGS_HAVE_VECTORCALL) и не обращается к `tp_call` в качестве запасного варианта.

Добавлено в версии 3.8.

## API вызова объектов

Доступны различные функции для вызова объекта Python. Каждая преобразует свои аргументы в соглашение, поддерживаемое вызываемым объектом – *tp\_call* или vectorcall. Чтобы выполнить как можно меньше преобразований, выбирайте ту, которая лучше всего подходит под формат имеющихся у вас данных.

В следующей таблице приведены доступные функции; подробнее см. в документации для каждой из них.

| Функция | вызываемый | аргументы | именованные аргументы |
| --- | --- | --- | --- |
| [`PyObject_Call()`](https://python-all.ru/3.13/c-api/call.html#c.PyObject_Call) | `PyObject *` | кортеж | словарь/`NULL` |
| [`PyObject_CallNoArgs()`](https://python-all.ru/3.13/c-api/call.html#c.PyObject_CallNoArgs) | `PyObject *` | – | – |
| [`PyObject_CallOneArg()`](https://python-all.ru/3.13/c-api/call.html#c.PyObject_CallOneArg) | `PyObject *` | 1 объект | – |
| [`PyObject_CallObject()`](https://python-all.ru/3.13/c-api/call.html#c.PyObject_CallObject) | `PyObject *` | кортеж/`NULL` | – |
| [`PyObject_CallFunction()`](https://python-all.ru/3.13/c-api/call.html#c.PyObject_CallFunction) | `PyObject *` | формат | – |
| [`PyObject_CallMethod()`](https://python-all.ru/3.13/c-api/call.html#c.PyObject_CallMethod) | объект + `char*` | формат | – |
| [`PyObject_CallFunctionObjArgs()`](https://python-all.ru/3.13/c-api/call.html#c.PyObject_CallFunctionObjArgs) | `PyObject *` | вариативный | – |
| [`PyObject_CallMethodObjArgs()`](https://python-all.ru/3.13/c-api/call.html#c.PyObject_CallMethodObjArgs) | объект + имя | вариативный | – |
| [`PyObject_CallMethodNoArgs()`](https://python-all.ru/3.13/c-api/call.html#c.PyObject_CallMethodNoArgs) | объект + имя | – | – |
| [`PyObject_CallMethodOneArg()`](https://python-all.ru/3.13/c-api/call.html#c.PyObject_CallMethodOneArg) | объект + имя | 1 объект | – |
| [`PyObject_Vectorcall()`](https://python-all.ru/3.13/c-api/call.html#c.PyObject_Vectorcall) | `PyObject *` | vectorcall | vectorcall |
| [`PyObject_VectorcallDict()`](https://python-all.ru/3.13/c-api/call.html#c.PyObject_VectorcallDict) | `PyObject *` | vectorcall | словарь/`NULL` |
| [`PyObject_VectorcallMethod()`](https://python-all.ru/3.13/c-api/call.html#c.PyObject_VectorcallMethod) | аргумент + имя | vectorcall | vectorcall |

#### `PyObject *PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)`

*Возвращаемое значение: новая ссылка.*

*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable).*

Вызывает вызываемый объект Python *callable* с аргументами, заданными кортежем *args*, и именованными аргументами, заданными словарём *kwargs*.

*args* не должен быть *NULL*; используйте пустой кортеж, если аргументы не нужны. Если именованные аргументы не нужны, *kwargs* может быть *NULL*.

Возвращает результат вызова при успехе или возбуждает исключение и возвращает *NULL* при неудаче.

Это эквивалент выражения Python: `callable(*args, **kwargs)`.

#### `PyObject *PyObject_CallNoArgs(PyObject *callable)`

*Возвращаемое значение: новая ссылка.*

*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable) начиная с версии 3.10.*

Вызывает вызываемый объект Python *callable* без аргументов. Это самый эффективный способ вызова вызываемого объекта Python без аргументов.

Возвращает результат вызова при успехе или возбуждает исключение и возвращает *NULL* при неудаче.

Добавлено в версии 3.9.

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

*Возвращаемое значение: новая ссылка.*

Вызывает вызываемый объект Python *callable* ровно с одним позиционным аргументом *arg* и без именованных аргументов.

Возвращает результат вызова при успехе или возбуждает исключение и возвращает *NULL* при неудаче.

Добавлено в версии 3.9.

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

*Возвращаемое значение: новая ссылка.*

*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable).*

Вызывает вызываемый объект Python *callable* с аргументами, заданными кортежем *args*. Если аргументы не нужны, *args* может быть *NULL*.

Возвращает результат вызова при успехе или возбуждает исключение и возвращает *NULL* при неудаче.

Это эквивалент выражения Python: `callable(*args)`.

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

*Возвращаемое значение: новая ссылка.*

*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable).*

Вызывает вызываемый объект Python *callable* с переменным числом аргументов C. Аргументы C описываются строкой формата в стиле [`Py_BuildValue()`](https://python-all.ru/3.13/c-api/arg.html#c.Py_BuildValue). Формат может быть *NULL*, что означает, что аргументы не предоставлены.

Возвращает результат вызова при успехе или возбуждает исключение и возвращает *NULL* при неудаче.

Это эквивалент выражения Python: `callable(*args)`.

Обратите внимание, что если передавать только аргументы [PyObject](https://python-all.ru/3.13/c-api/structures.html#c.PyObject)\*, то [`PyObject_CallFunctionObjArgs()`](https://python-all.ru/3.13/c-api/call.html#c.PyObject_CallFunctionObjArgs) будет более быстрой альтернативой.

Изменено в версии 3.4: Тип *format* был изменён с `char *`.

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

*Возвращаемое значение: новая ссылка.*

*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable).*

Вызывает метод с именем *name* объекта *obj* с переменным числом аргументов C. Аргументы C описываются строкой формата [`Py_BuildValue()`](https://python-all.ru/3.13/c-api/arg.html#c.Py_BuildValue), которая должна порождать кортеж.

Формат может быть *NULL*, что означает, что аргументы не предоставлены.

Возвращает результат вызова при успехе или возбуждает исключение и возвращает *NULL* при неудаче.

Это эквивалент выражения Python: `obj.name(arg1, arg2, ...)`.

Обратите внимание, что если передавать только аргументы [PyObject](https://python-all.ru/3.13/c-api/structures.html#c.PyObject)\*, то [`PyObject_CallMethodObjArgs()`](https://python-all.ru/3.13/c-api/call.html#c.PyObject_CallMethodObjArgs) будет более быстрой альтернативой.

Изменено в версии 3.4: Типы *name* и *format* были изменены с `char *`.

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

*Возвращаемое значение: новая ссылка.*

*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable).*

Вызывает вызываемый объект Python *callable* с переменным числом аргументов [PyObject](https://python-all.ru/3.13/c-api/structures.html#c.PyObject)\*. Аргументы передаются как переменное число параметров, за которым следует *NULL*.

Возвращает результат вызова при успехе или возбуждает исключение и возвращает *NULL* при неудаче.

Это эквивалент выражения Python: `callable(arg1, arg2, ...)`.

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

*Возвращаемое значение: новая ссылка.*

*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable).*

Вызывает метод объекта Python *obj*, где имя метода задаётся как строковый объект Python в *name*. Он вызывается с переменным числом аргументов [PyObject](https://python-all.ru/3.13/c-api/structures.html#c.PyObject)\*. Аргументы передаются как переменное число параметров, за которым следует *NULL*.

Возвращает результат вызова при успехе или возбуждает исключение и возвращает *NULL* при неудаче.

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

Вызывает метод объекта Python *obj* без аргументов, где имя метода задаётся как строковый объект Python в *name*.

Возвращает результат вызова при успехе или возбуждает исключение и возвращает *NULL* при неудаче.

Добавлено в версии 3.9.

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

Вызывает метод объекта Python *obj* с одним позиционным аргументом *arg*, где имя метода задаётся как строковый объект Python в *name*.

Возвращает результат вызова при успехе или возбуждает исключение и возвращает *NULL* при неудаче.

Добавлено в версии 3.9.

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

*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable) начиная с версии 3.12.*

Вызывает вызываемый объект Python *callable*. Аргументы те же, что и для [`vectorcallfunc`](https://python-all.ru/3.13/c-api/call.html#c.vectorcallfunc). Если *callable* поддерживает [vectorcall](https://python-all.ru/3.13/c-api/call.html#vectorcall), то эта функция напрямую вызывает функцию vectorcall, хранящуюся в *callable*.

Возвращает результат вызова при успехе или возбуждает исключение и возвращает *NULL* при неудаче.

Добавлено в версии 3.8: как `_PyObject_Vectorcall`

Изменено в версии 3.9: Переименовано в текущее имя без ведущего подчёркивания. Старое временное имя [мягко устарело](https://python-all.ru/3.13/glossary.html#term-soft-deprecated).

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

Вызывает *callable* с позиционными аргументами, передаваемыми точно так же, как в протоколе [vectorcall](https://python-all.ru/3.13/c-api/call.html#vectorcall), но с именованными аргументами, передаваемыми в виде словаря *kwdict*. Массив *args* содержит только позиционные аргументы.

Независимо от того, какой протокол используется внутри, требуется выполнить преобразование аргументов. Поэтому эту функцию следует использовать только в том случае, если у вызывающего кода уже есть словарь, готовый для именованных аргументов, но нет кортежа для позиционных аргументов.

Добавлено в версии 3.9.

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

*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable) начиная с версии 3.12.*

Вызывает метод, используя соглашение о вызове vectorcall. Имя метода задаётся в виде строки Python *name*. Объект, чей метод вызывается – это *args\[0\]*, а массив *args*, начиная с *args\[1\]*, представляет аргументы вызова. Должен присутствовать хотя бы один позиционный аргумент. *nargsf* – это количество позиционных аргументов, включая *args\[0\]*, плюс [`PY_VECTORCALL_ARGUMENTS_OFFSET`](https://python-all.ru/3.13/c-api/call.html#c.PY_VECTORCALL_ARGUMENTS_OFFSET), если значение `args[0]` может временно изменяться. Именованные аргументы можно передавать так же, как в [`PyObject_Vectorcall()`](https://python-all.ru/3.13/c-api/call.html#c.PyObject_Vectorcall).

Если объект обладает возможностью [`Py_TPFLAGS_METHOD_DESCRIPTOR`](https://python-all.ru/3.13/c-api/typeobj.html#c.Py_TPFLAGS_METHOD_DESCRIPTOR), то будет вызван непривязанный объект метода с полным вектором *args* в качестве аргументов.

Возвращает результат вызова при успехе или возбуждает исключение и возвращает *NULL* при неудаче.

Добавлено в версии 3.9.

## API поддержки вызова

#### `int PyCallable_Check(PyObject *o)`

*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable).*

Определяет, является ли объект *o* вызываемым. Возвращает `1`, если объект вызываем, и `0` в противном случае. Эта функция всегда завершается успешно.
