Протокол вызова
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. Это указатель на функцию со следующей подписью:
-
typedef 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для поддержки будущих расширений.Введено в версии 3.8.
-
vectorcallfunc PyVectorcall_Function(PyObject *op) -
Если op не поддерживает протокол vectorcall (либо из-за типа, либо из-за конкретного экземпляра), вернуть NULL. В противном случае вернуть указатель на функцию vectorcall, хранящийся в op. Эта функция никогда не вызывает исключения.
Это в основном полезно для проверки того, поддерживает ли op vectorcall, что можно сделать, проверив
PyVectorcall_Function(op) != NULL.Введено в версии 3.8.
-
PyObject *PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *dict) -
Вызвать
vectorcallfunccallable с позиционными и именованными аргументами, заданными в кортеже и словаре соответственно.Это специализированная функция, предназначенная для размещения в слоте
tp_callили использования в реализацииtp_call. Она не проверяет флагPy_TPFLAGS_HAVE_VECTORCALLи не переходит наtp_call.Введено в версии 3.8.
Вызов API объекта
Доступны различные функции для вызова Python-объекта. Каждая преобразует свои аргументы в конвенцию, поддерживаемую вызываемым объектом — либо tp_call, либо vectorcall. Для минимизации преобразований выбирайте функцию, которая лучше всего подходит для формата имеющихся данных.
Следующая таблица обобщает доступные функции; подробности см. в отдельных документах.
Функция | вызываемый объект | аргументы | именованные аргументы |
|---|---|---|---|
| кортеж | словарь/ | |
| — | — | |
| 1 объект | — | |
| кортеж/ | — | |
| формат | — | |
объект + | формат | — | |
| переменное количество | — | |
объект + имя | переменное количество | — | |
объект + имя | — | — | |
объект + имя | 1 объект | — | |
| vectorcall | vectorcall | |
| vectorcall | словарь/ | |
арг + имя | vectorcall | vectorcall |
-
PyObject *PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs) -
Возвращаемое значение: новая ссылка. Часть Стабильной ABI.
Вызов вызываемого Python-объекта вызываемый объект с аргументами, заданными кортежем args, и именованными аргументами, заданными словарем kwargs.
args не должен быть NULL; используйте пустой кортеж, если аргументы не нужны. Если именованные аргументы не нужны, kwargs может быть NULL.
Возвращает результат вызова при успехе или генерирует исключение и возвращает NULL при ошибке.
Это эквивалентно выражению Python:
callable(*args, **kwargs).
-
PyObject *PyObject_CallNoArgs(PyObject *callable) -
Часть Стабильной ABI с версии 3.10.
Вызов вызываемого Python-объекта вызываемый объект без каких-либо аргументов. Это наиболее эффективный способ вызова вызываемого Python-объекта без аргументов.
Возвращает результат вызова при успехе или генерирует исключение и возвращает NULL при ошибке.
Введено в версии 3.9.
-
PyObject *PyObject_CallOneArg(PyObject *callable, PyObject *arg) -
Вызов вызываемого Python-объекта вызываемый объект с ровно 1 позиционным аргументом arg и без именованных аргументов.
Возвращает результат вызова при успехе или генерирует исключение и возвращает NULL при ошибке.
Введено в версии 3.9.
-
PyObject *PyObject_CallObject(PyObject *callable, PyObject *args) -
Возвращаемое значение: новая ссылка. Часть Стабильной ABI.
Вызов вызываемого Python-объекта вызываемый объект с аргументами, заданными кортежем args. Если аргументы не нужны, то args может быть NULL.
Возвращает результат вызова при успехе или генерирует исключение и возвращает NULL при ошибке.
Это эквивалентно выражению Python:
callable(*args).
-
PyObject *PyObject_CallFunction(PyObject *callable, const char *format, ...) -
Возвращаемое значение: новая ссылка. Часть Стабильной ABI.
Вызов вызываемого Python-объекта вызываемый объект с переменным количеством 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, ...) -
Возвращаемое значение: новая ссылка. Часть Стабильной ABI.
Вызов метода 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, ...) -
Возвращаемое значение: новая ссылка. Часть Стабильной ABI.
Вызов вызываемого Python-объекта вызываемый объект с переменным количеством
PyObject*аргументов. Аргументы передаются как переменное количество параметров, за которым следует NULL.Возвращает результат вызова при успехе или генерирует исключение и возвращает NULL при ошибке.
Это эквивалентно выражению Python:
callable(arg1, arg2, ...).
-
PyObject *PyObject_CallMethodObjArgs(PyObject *obj, PyObject *name, ...) -
Возвращаемое значение: новая ссылка. Часть Стабильной ABI.
Вызов метода Python-объекта obj, где имя метода задаётся как Python-строковый объект в name. Вызов производится с переменным количеством
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) -
Вызов вызываемого Python-объекта вызываемый объект. Аргументы такие же, как у
vectorcallfunc. Если вызываемый объект поддерживает vectorcall, это напрямую вызывает функцию vectorcall, хранящуюся в вызываемый объект.Возвращает результат вызова при успехе или генерирует исключение и возвращает NULL при ошибке.
Введено в версии 3.9.
-
PyObject *PyObject_VectorcallDict(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwdict) -
Вызов callable с позиционными аргументами, передаваемыми точно так же, как в протоколе vectorcall, но с ключевыми аргументами, переданными как словарь kwdict. Массив args содержит только позиционные аргументы.
Независимо от используемого внутреннего протокола, требуется преобразование аргументов. Поэтому эту функцию следует использовать только в том случае, если вызывающая сторона уже имеет словарь, готовый к использованию для ключевых аргументов, но не кортеж для позиционных аргументов.
Новая в версии 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 при ошибке.
Новая в версии 3.9.
API поддержки вызовов
-
int PyCallable_Check(PyObject *o) -
Часть Стабильной ABI.
Определяет, является ли объект o вызываемым. Возвращает
1, если объект вызываемый, и0в противном случае. Эта функция всегда выполняется успешно.
© 2001–2023 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.10/c-api/call.html