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

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

Нове в версії 3.9.

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

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

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

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

Клас не повинен реалізовувати 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:

PyObject *(*vectorcallfunc)(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames)
  • 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

Якщо цей прапор встановлено в аргументі 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.

Щоб викликати об’єкт, який реалізує 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 абонентам не потрібно турбуватися про recursion: CPython використовує Py_EnterRecursiveCall() і Py_LeaveRecursiveCall() для викликів, здійснених за допомогою tp_call.

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

API підтримки Vectorcall

Py_ssize_t PyVectorcall_NARGS(size_t nargsf)

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

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)

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

This function is not part of the limited API.

Нове в версії 3.8.

vectorcallfunc PyVectorcall_Function(PyObject *op)

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

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

This function is not part of the limited API.

Нове в версії 3.8.

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

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

This function is not part of the limited API.

Нове в версії 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.

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

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

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

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

PyObject* PyObject_CallNoArgs(PyObject *callable)

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

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

Нове в версії 3.9.

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

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

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

This function is not part of the limited API.

Нове в версії 3.9.

PyObject* PyObject_CallObject(PyObject *callable, PyObject *args)
Return value: New reference.

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

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

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

PyObject* PyObject_CallFunction(PyObject *callable, const char *format, ...)
Return value: New reference.

Викликайте об’єкт 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.

Викличте метод з назвою 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.

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)

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

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

This function is not part of the limited API.

Нове в версії 3.9.

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

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

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

This function is not part of the limited API.

Нове в версії 3.9.

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

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

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

This function is not part of the limited API.

Нове в версії 3.9.

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

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

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

This function is not part of the 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 у разі невдачі.

This function is not part of the limited API.

Нове в версії 3.9.

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

int PyCallable_Check(PyObject *o)

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