# Протокол виклику

CPython підтримує два різні протоколи виклику: tp_call і vectorcall.

## Протокол tp_call

Примірники класів, які встановлюють `tp_call`, можна викликати. Сигнатура слота:

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

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

Ця угода використовується не лише tp_call: `tp_new` і `tp_init` також передають аргументи таким чином.

Щоб викликати об’єкт, використовуйте `PyObject_Call()` або інший API виклику.

## Протокол Vectorcall

Added in version 3.9.

Протокол vectorcall був представлений у PEP 590 як додатковий протокол для підвищення ефективності викликів.

Як правило, CPython віддасть перевагу vectorcall для внутрішніх викликів, якщо виклик підтримує його. Однак це не жорстке правило. Крім того, деякі сторонні розширення використовують безпосередньо tp_call (замість використання `PyObject_Call()`). Таким чином, клас, який підтримує векторний виклик, також повинен реалізовувати `tp_call`. Крім того, виклик має вести себе однаково незалежно від того, який протокол використовується. Рекомендований спосіб досягти цього — встановити `tp_call` на `PyVectorcall_Call()`. Варто повторити:

Попередження

Клас, що підтримує векторний виклик, повинен також реалізувати `tp_call` з тією самою семантикою.

Змінено в версії 3.12: The `Py_TPFLAGS_HAVE_VECTORCALL` flag is now removed from a class when the class’s `__call__()` method is reassigned. (This internally sets `tp_call` only, and thus may make it behave differently than the vectorcall function.) In earlier Python versions, vectorcall should only be used with `immutable` or static types.

Клас не повинен реалізовувати vectorcall, якщо це буде повільніше, ніж tp_call. Наприклад, якщо викликаному потрібно перетворити аргументи на кортеж args і kwargs dict у будь-якому випадку, тоді немає сенсу в реалізації vectorcall.

Classes can implement the vectorcall protocol by enabling the `Py_TPFLAGS_HAVE_VECTORCALL` flag and setting `tp_vectorcall_offset` to the offset inside the object structure where a vectorcallfunc appears. This is a pointer to a function with the following signature:

typedef PyObject *(*vectorcallfunc)(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames)
  Part of the Stable ABI since version 3.12.

- callable — об’єкт, який викликається.

- args — це масив C, що складається з позиційних аргументів, за якими йде

    значення аргументів ключових слів. Це може бути NULL, якщо немає аргументів.

- nargsf — це кількість позиційних аргументів плюс, можливо,

    `PY_VECTORCALL_ARGUMENTS_OFFSET` flag. To get the actual number of positional arguments from nargsf, use `PyVectorcall_NARGS()`.

- kwnames — це кортеж, що містить імена аргументів ключових слів;

    іншими словами, ключі kwargs dict. Ці імена мають бути рядками (примірниками `str` або підкласом) і вони мають бути унікальними. Якщо аргументів ключового слова немає, замість цього kwnames може бути NULL.

PY_VECTORCALL_ARGUMENTS_OFFSET
  Part of the Stable ABI since version 3.12.

  Якщо цей прапор встановлено в аргументі nargsf векторного виклику, викликаному дозволено тимчасово змінювати `args[-1]`. Іншими словами, args вказує на аргумент 1 (а не 0) у виділеному векторі. Викликаний має відновити значення `args[-1]` перед поверненням.

  Для `PyObject_VectorcallMethod()` цей прапорець натомість означає, що `args[0]` можна змінити.

  Whenever they can do so cheaply (without additional allocation), callers are encouraged to use `PY_VECTORCALL_ARGUMENTS_OFFSET`. Doing so will allow callables such as bound methods to make their onward calls (which include a prepended self argument) very efficiently.

  Added in version 3.8.

Щоб викликати об’єкт, який реалізує vectorcall, скористайтеся call API функцією, як і будь-якою іншою можливістю виклику. `PyObject_Vectorcall()` зазвичай буде найефективнішим.

### Контроль рекурсії

Під час використання tp_call абонентам не потрібно турбуватися про recursion: CPython використовує `Py_EnterRecursiveCall()` і `Py_LeaveRecursiveCall()` для викликів, здійснених за допомогою tp_call.

Для ефективності це не стосується викликів, виконаних за допомогою vectorcall: виклик має використовувати Py_EnterRecursiveCall і Py_LeaveRecursiveCall, якщо це необхідно.

### API підтримки Vectorcall

Py_ssize_t PyVectorcall_NARGS(size_t nargsf)
  Part of the Stable ABI since version 3.12.

  За наявності аргументу nargsf для векторного виклику повертає фактичну кількість аргументів. На даний момент еквівалентно:

      (Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)

  Проте, функція `PyVectorcall_NARGS` повинна використовуватися, щоб дозволити майбутні розширення.

  Added in version 3.8.

vectorcallfunc PyVectorcall_Function(PyObject *op)

  Якщо op не підтримує протокол vectorcall (або тому, що тип не підтримує, або тому, що конкретний екземпляр не підтримує), повертає NULL. В іншому випадку поверніть покажчик функції vectorcall, що зберігається в op. Ця функція ніколи не викликає винятків.

  Це здебільшого корисно, щоб перевірити, чи op підтримує векторний виклик, що можна зробити, перевіривши `PyVectorcall_Function(op) != NULL`.

  Added in version 3.9.

PyObject *PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *dict)
  Part of the Stable ABI since version 3.12.

  Викликати callable `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`.

  Added in version 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 *` | векторний виклик | векторний виклик
`PyObject_VectorcallDict()` | `PyObject *` | векторний виклик | dict/`NULL`
`PyObject_VectorcallMethod()` | аргумент + ім’я | векторний виклик | векторний виклик

PyObject *PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
  Return value: New reference. Part of the Stable ABI.

  Викликайте викликний об’єкт Python callable з аргументами, заданими кортежем args, і іменованими аргументами, заданими словником kwargs.

  args не має бути NULL; використовуйте порожній кортеж, якщо аргументи не потрібні. Якщо іменовані аргументи не потрібні, kwargs може бути NULL.

  Повернути результат виклику в разі успіху або створити виняток і повернути NULL у разі невдачі.

  Це еквівалент виразу Python: `callable(*args, **kwargs)`.

PyObject *PyObject_CallNoArgs(PyObject *callable)
  Return value: New reference. Part of the Stable ABI since version 3.10.

  Викликати об’єкт Python, який можна викликати, callable без аргументів. Це найефективніший спосіб викликати викликаний об’єкт Python без будь-яких аргументів.

  Повернути результат виклику в разі успіху або створити виняток і повернути NULL у разі невдачі.

  Added in version 3.9.

PyObject *PyObject_CallOneArg(PyObject *callable, PyObject *arg)
  Return value: New reference.

  Викликайте об’єкт Python, який можна викликати, callable, точно 1 позиційний аргумент arg і без ключових аргументів.

  Повернути результат виклику в разі успіху або створити виняток і повернути NULL у разі невдачі.

  Added in version 3.9.

PyObject *PyObject_CallObject(PyObject *callable, PyObject *args)
  Return value: New reference. Part of the Stable ABI.

  Викликайте викликний об’єкт Python callable з аргументами, заданими кортежем args. Якщо аргументи не потрібні, args може бути NULL.

  Повернути результат виклику в разі успіху або створити виняток і повернути NULL у разі невдачі.

  Це еквівалент виразу Python: `callable(*args)`.

PyObject *PyObject_CallFunction(PyObject *callable, const char *format, ...)
  Return value: New reference. Part of the Stable ABI.

  Викликайте об’єкт Python, який можна викликати, callable, зі змінною кількістю аргументів C. Аргументи C описані за допомогою рядка формату стилю `Py_BuildValue()`. Формат може бути NULL, що вказує на відсутність аргументів.

  Повернути результат виклику в разі успіху або створити виняток і повернути 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. Part of the Stable ABI.

  Викличте метод з назвою name об’єкта obj зі змінною кількістю аргументів C. Аргументи C описуються рядком формату `Py_BuildValue()`, який має створити кортеж.

  Формат може бути NULL, що вказує на відсутність аргументів.

  Повернути результат виклику в разі успіху або створити виняток і повернути NULL у разі невдачі.

  Це еквівалент виразу Python: `obj.name(arg1, arg2, ...)`.

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

  Змінено в версії 3.4: Типи name і format були змінені з `char *`.

PyObject *PyObject_CallFunctionObjArgs(PyObject *callable, ...)
  Return value: New reference. Part of the Stable ABI.

  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. Part of the Stable ABI.

  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)

  Виклик методу об’єкта Python obj без аргументів, де ім’я методу вказано як рядковий об’єкт Python у name.

  Повернути результат виклику в разі успіху або створити виняток і повернути NULL у разі невдачі.

  Added in version 3.9.

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

  Викличте метод об’єкта Python obj за допомогою одного позиційного аргументу arg, де ім’я методу вказано як рядковий об’єкт Python у name.

  Повернути результат виклику в разі успіху або створити виняток і повернути NULL у разі невдачі.

  Added in version 3.9.

PyObject *PyObject_Vectorcall(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames)
  Part of the Stable ABI since version 3.12.

  Викликайте викликаний об’єкт Python callable. Аргументи такі самі, як і для `vectorcallfunc`. Якщо callable підтримує vectorcall, це безпосередньо викликає функцію vectorcall, збережену в callable.

  Повернути результат виклику в разі успіху або створити виняток і повернути NULL у разі невдачі.

  Added in version 3.8: as `_PyObject_Vectorcall`

  Змінено в версії 3.9: Renamed to the current name, without the leading underscore. The old provisional name is soft deprecated.

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

  Виклик callable з позиційними аргументами, що передаються точно так само, як у протоколі vectorcall, але з ключовими аргументами, що передаються як словник kwdict. Масив args містить лише позиційні аргументи.

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

  Added in version 3.9.

PyObject *PyObject_VectorcallMethod(PyObject *name, PyObject *const *args, size_t nargsf, PyObject *kwnames)
  Part of the Stable ABI since version 3.12.

  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 у разі невдачі.

  Added in version 3.9.

## API виклику служби підтримки

int PyCallable_Check(PyObject *o)
  Part of the Stable ABI.

  Визначте, чи можна викликати об’єкт o. Повертає `1`, якщо об’єкт можна викликати, і `0` інакше. Ця функція завжди успішна.