Протокол вызова
CPython поддерживает два различных протокола вызова: tp_call и vectorcall.
Протокол tp_call
Объекты классов, которые устанавливают tp_call, являются вызываемыми. Подпись слота:
PyObject *tp_call(PyObject *callable, PyObject *args, PyObject *kwargs);
Вызов осуществляется с использованием кортежа для позиционных аргументов и словаря для именованных аргументов, аналогично 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()). Поэтому класс, поддерживающий vectorcall, должен также реализовывать tp_call. Более того, вызываемый объект должен вести себя одинаково независимо от используемого протокола. Рекомендуемый способ достижения этого — установка tp_call на PyVectorcall_Call(). Это следует повторить:
Предупреждение
Класс, поддерживающий vectorcall, должен также реализовывать tp_call с той же семантикой.
Класс не должен реализовывать vectorcall, если это будет медленнее, чем tp_call. Например, если вызываемому объекту всё равно необходимо преобразовывать аргументы в кортеж args и словарь kwargs, то нет смысла реализовывать vectorcall.
Классы могут реализовывать протокол vectorcall, включив флаг Py_TPFLAGS_HAVE_VECTORCALL и установив tp_vectorcall_offset на смещение внутри структуры объекта, где появляется vectorcallfunc. Это указатель на функцию со следующей подписью:
-
PyObject *(*vectorcallfunc)(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames)
- callable — вызываемый объект.
-
- args — массив C, содержащий позиционные аргументы, за которыми следуют
-
значения именованных аргументов. Он может быть NULL, если аргументов нет.
-
- nargsf — количество позиционных аргументов плюс, возможно,
-
PY_VECTORCALL_ARGUMENTS_OFFSETфлаг. Чтобы получить фактическое количество позиционных аргументов из nargsf, используйтеPyVectorcall_NARGS().
-
- kwnames — кортеж, содержащий имена именованных аргументов;
-
другими словами, ключи словаря kwargs. Эти имена должны быть строками (объектами типа
strили подкласса) и они должны быть уникальными. Если именованных аргументов нет, то kwnames может быть NULL.
-
PY_VECTORCALL_ARGUMENTS_OFFSET -
Если этот флаг установлен в аргументе nargsf vectorcall, вызываемому объекту разрешается временно изменить
args[-1]. Другими словами, args указывает на аргумент 1 (а не 0) в выделенном векторе. Вызываемый объект должен восстановить значениеargs[-1]перед возвратом.Для
PyObject_VectorcallMethod()этот флаг означает, чтоargs[0]может быть изменён.Всякий раз, когда они могут сделать это недорого (без дополнительного выделения), вызывающие объекты должны использовать
PY_VECTORCALL_ARGUMENTS_OFFSET. Это позволит таким вызываемым объектам, как связанные методы, выполнять последующие вызовы (включая предваряющий аргумент self) очень эффективно.
Для вызова объекта, реализующего vectorcall, используйте функцию API вызова как и для любого другого вызываемого объекта. PyObject_Vectorcall() обычно будет наиболее эффективным.
Примечание
В CPython 3.8 API vectorcall и связанные функции были доступны предварительно под именами с префиксным символом подчёркивания: _PyObject_Vectorcall, _Py_TPFLAGS_HAVE_VECTORCALL, _PyObject_VectorcallMethod, _PyVectorcall_Function, _PyObject_CallOneArg, _PyObject_CallMethodNoArgs, _PyObject_CallMethodOneArg. Кроме того, PyObject_VectorcallDict был доступен как _PyObject_FastCallDict. Старые имена всё ещё определены как алиасы новых, без префикса подчёркивания.
Управление рекурсией
При использовании tp_call вызываемым объектам не нужно беспокоиться о рекурсии: CPython использует Py_EnterRecursiveCall() и Py_LeaveRecursiveCall() для вызовов, выполненных с использованием tp_call.
Для повышения эффективности это не так для вызовов, выполненных с использованием vectorcall: вызываемый объект должен использовать Py_EnterRecursiveCall и Py_LeaveRecursiveCall при необходимости.
API поддержки Vectorcall
-
Py_ssize_t PyVectorcall_NARGS(size_t nargsf) -
На основе аргумента nargsf vectorcall возвращает фактическое количество аргументов. В настоящее время эквивалентно:
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
Однако, следует использовать функцию
PyVectorcall_NARGSдля будущих расширений.Эта функция не входит в ограниченный API.
Новое в версии 3.8.
-
vectorcallfunc PyVectorcall_Function(PyObject *op) -
Если op не поддерживает протокол vectorcall (либо из-за типа, либо из-за конкретного экземпляра), возвращает NULL. В противном случае, возвращает указатель на функцию vectorcall, хранящийся в op. Эта функция никогда не генерирует исключений.
Это в основном полезно для проверки поддержки протокола vectorcall в op, что можно сделать, проверив
PyVectorcall_Function(op) != NULL.Эта функция не входит в ограниченный API.
Новое в версии 3.8.
-
PyObject* PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *dict) -
Вызывает
vectorcallfuncобъекта callable с позиционными и именованными аргументами, заданными в кортеже и словаре соответственно.Это специализированная функция, предназначенная для размещения в слоте
tp_callили использования в реализацииtp_call. Она не проверяет флагPy_TPFLAGS_HAVE_VECTORCALLи не возвращается кtp_call.Эта функция не входит в ограниченный API.
Новое в версии 3.8.
Вызов API объектов
Доступны различные функции для вызова объекта Python. Каждая преобразует свои аргументы в соглашение, поддерживаемое вызываемым объектом — либо tp_call, либо vectorcall. Чтобы свести к минимуму преобразования, выберите функцию, которая лучше всего соответствует формату доступных данных.
Следующая таблица обобщает доступные функции; подробные сведения см. в индивидуальной документации.
Функция | вызываемый | args | kwargs |
|---|---|---|---|
| кортеж | словарь/ | |
| — | — | |
| 1 объект | — | |
| кортеж/ | — | |
| формат | — | |
объект + | формат | — | |
| переменная длина | — | |
объект + имя | переменная длина | — | |
объект + имя | — | — | |
объект + имя | 1 объект | — | |
| vectorcall | vectorcall | |
| vectorcall | словарь/ | |
аргумент + имя | vectorcall | vectorcall |
-
PyObject* PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs) -
Значение возврата: новая ссылка.
Вызов вызываемого объекта 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 при ошибке.
Эта функция не является частью ограниченного API.
Введено в версии 3.9.
-
PyObject* PyObject_CallObject(PyObject *callable, PyObject *args) -
Значение возврата: новая ссылка.
Вызов вызываемого объекта Python callable с аргументами, заданными кортежем args. Если аргументы не нужны, то args может быть NULL.
Возвращает результат вызова при успехе или генерирует исключение и возвращает NULL при ошибке.
Эквивалентно выражению Python:
callable(*args).
-
PyObject* PyObject_CallFunction(PyObject *callable, const char *format, ...) -
Значение возврата: новая ссылка.
Вызов вызываемого объекта Python callable с переменным числом аргументов C. Аргументы C описываются с помощью строки формата в стиле
Py_BuildValue(). Формат может быть NULL, указывая, что аргументы не предоставляются.Возвращает результат вызова при успехе или генерирует исключение и возвращает NULL при ошибке.
Эквивалентно выражению Python:
callable(*args).Обратите внимание, что если вы передаете только аргументы
PyObject *,PyObject_CallFunctionObjArgs()— более быстрый вариант.Изменено в версии 3.4: Тип формата был изменен с
char *.
-
PyObject* PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...) -
Значение возврата: новая ссылка.
Вызов метода с именем name объекта obj с переменным числом аргументов C. Аргументы C описываются строкой формата
Py_BuildValue(), которая должна генерировать кортеж.Формат может быть NULL, указывая, что аргументы не предоставляются.
Возвращает результат вызова при успехе или генерирует исключение и возвращает NULL при ошибке.
Эквивалентно выражению Python:
obj.name(arg1, arg2, ...).Обратите внимание, что если вы передаете только аргументы
PyObject *,PyObject_CallMethodObjArgs()— более быстрый вариант.Изменено в версии 3.4: Типы name и формат были изменены с
char *.
-
PyObject* PyObject_CallFunctionObjArgs(PyObject *callable, ...) -
Значение возврата: новая ссылка.
Вызов вызываемого объекта Python callable с переменным числом аргументов
PyObject *. Аргументы предоставляются как переменное число параметров, за которым следует NULL.Возвращает результат вызова при успехе или генерирует исключение и возвращает NULL при ошибке.
Эквивалентно выражению Python:
callable(arg1, arg2, ...).
-
PyObject* PyObject_CallMethodObjArgs(PyObject *obj, PyObject *name, ...) -
Значение возврата: новая ссылка.
Вызов метода объекта Python obj, где имя метода задается объектом Python-строки в name. Вызывается с переменным числом аргументов
PyObject *. Аргументы предоставляются как переменное число параметров, за которым следует NULL.Возвращает результат вызова при успехе или генерирует исключение и возвращает NULL при ошибке.
-
PyObject* PyObject_CallMethodNoArgs(PyObject *obj, PyObject *name) -
Вызов метода объекта Python obj без аргументов, где имя метода задается объектом Python-строки в name.
Возвращает результат вызова при успехе или генерирует исключение и возвращает NULL при ошибке.
Эта функция не является частью ограниченного API.
Введено в версии 3.9.
-
PyObject* PyObject_CallMethodOneArg(PyObject *obj, PyObject *name, PyObject *arg) -
Вызов метода объекта Python obj с одним позиционным аргументом arg, где имя метода задается объектом Python-строки в name.
Возвращает результат вызова при успехе или генерирует исключение и возвращает NULL при ошибке.
Эта функция не является частью ограниченного API.
Введено в версии 3.9.
-
PyObject* PyObject_Vectorcall(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames) -
Вызов вызываемого объекта Python callable. Аргументы такие же, как у
vectorcallfunc. Если callable поддерживает vectorcall, это напрямую вызывает функцию vectorcall, сохраненную в callable.Возвращает результат вызова при успехе или генерирует исключение и возвращает NULL при ошибке.
Эта функция не является частью ограниченного API.
Введено в версии 3.9.
-
PyObject* PyObject_VectorcallDict(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwdict) -
Вызов callable с позиционными аргументами, переданными точно так же, как в протоколе vectorcall, но с ключевыми аргументами, переданными в виде словаря kwdict. Массив args содержит только позиционные аргументы.
Независимо от того, какой протокол используется внутри, необходимо выполнить преобразование аргументов. Поэтому эту функцию следует использовать только в том случае, если у вызывающей стороны уже есть словарь, готовый к использованию для ключевых аргументов, но нет кортежа для позиционных аргументов.
Эта функция не входит в ограниченный API.
Новая в версии 3.9.
-
PyObject* PyObject_VectorcallMethod(PyObject *name, PyObject *const *args, size_t nargsf, PyObject *kwnames) -
Вызов метода с использованием соглашения о вызове vectorcall. Имя метода задаётся как строка Python name. Объект, метод которого вызывается, — args[0], а массив args, начиная с args[1], представляет аргументы вызова. Должен быть хотя бы один позиционный аргумент. nargsf — количество позиционных аргументов, включая args[0], плюс
PY_VECTORCALL_ARGUMENTS_OFFSETесли значениеargs[0]может быть временно изменено. Ключевые аргументы могут передаваться так же, как и вPyObject_Vectorcall().Если у объекта есть функция
Py_TPFLAGS_METHOD_DESCRIPTOR, это вызовет неопределённый объект метода с полным вектором args в качестве аргументов.Возвращает результат вызова при успехе или поднимает исключение и возвращает NULL при ошибке.
Эта функция не входит в ограниченный API.
Новая в версии 3.9.
API поддержки вызовов
-
int PyCallable_Check(PyObject *o) -
Определяет, является ли объект o вызываемым. Возвращает
1если объект вызываемый и0в противном случае. Эта функция всегда выполняется успешно.
© 2001–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.9/c-api/call.html