Протокол виклику¶
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, usePyVectorcall_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 oftp_call
. It does not check thePy_TPFLAGS_HAVE_VECTORCALL
flag and it does not fall back totp_call
.This function is not part of the limited API.
Нове в версії 3.8.
API виклику об’єктів¶
Для виклику об’єкта Python доступні різні функції. Кожен перетворює свої аргументи на конвенцію, яка підтримується викликаним об’єктом – tp_call або vectorcall. Щоб зробити якомога менше перетворення, виберіть той, який найкраще відповідає формату доступних даних.
У наведеній нижче таблиці підсумовано доступні функції; подробиці див. в індивідуальній документації.
функція |
викликний |
арг |
kwargs |
---|---|---|---|
|
кортеж |
dict/ |
|
|
— |
— |
|
|
1 об’єкт |
— |
|
|
кортеж/ |
— |
|
|
формат |
— |
|
obj + |
формат |
— |
|
|
варіативний |
— |
|
obj + ім’я |
варіативний |
— |
|
obj + ім’я |
— |
— |
|
obj + ім’я |
1 об’єкт |
— |
|
|
векторний виклик |
векторний виклик |
|
|
векторний виклик |
dict/ |
|
аргумент + ім’я |
векторний виклик |
векторний виклик |
-
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 ofargs[0]
may temporarily be changed. Keyword arguments can be passed just like inPyObject_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.