Протокол вызова
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 с теми же семантиками.
Изменено в версии 3.12: Флаг Py_TPFLAGS_HAVE_VECTORCALL теперь удаляется из класса, когда метод __call__() класса переопределяется. (Это внутренне устанавливает только tp_call, и, следовательно, может привести к поведению, отличающемуся от функции vectorcall.) В более ранних версиях Python vectorcall следует использовать только с immutable или статическими типами.
Класс не должен реализовывать 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) - Часть Стабильной ABI с версии 3.12.
- callable — вызываемый объект.
-
- args — массив C, состоящий из позиционных аргументов, за которыми следуют
-
значения именованных аргументов. Может быть NULL, если аргументов нет.
-
- nargsf — количество позиционных аргументов плюс, возможно,
-
флаг
PY_VECTORCALL_ARGUMENTS_OFFSET. Чтобы получить фактическое количество позиционных аргументов из nargsf, используйтеPyVectorcall_NARGS().
-
- kwnames — кортеж, содержащий имена именованных аргументов;
-
другими словами, ключи словаря kwargs. Эти имена должны быть строками (экземпляры
strили подкласса) и должны быть уникальными. Если именованных аргументов нет, то kwnames может быть NULL.
-
PY_VECTORCALL_ARGUMENTS_OFFSET -
Часть Стабильной ABI с версии 3.12.
Если этот флаг установлен в аргументе nargsf vectorcall, вызываемому объекту разрешено временно изменить
args[-1]. Другими словами, args указывает на аргумент 1 (а не 0) в выделенном векторе. Вызываемый объект должен восстановить значениеargs[-1]перед возвратом.Для
PyObject_VectorcallMethod()этот флаг означает, чтоargs[0]может быть изменён.В тех случаях, когда это можно сделать с небольшой затратой (без дополнительного выделения), вызывающим сторонам рекомендуется использовать
PY_VECTORCALL_ARGUMENTS_OFFSET. Это позволит вызываемым объектам, таким как связанные методы, выполнять последующие вызовы (включая предварительно добавленный аргумент self) очень эффективно.Добавлен в версии 3.8.
Для вызова объекта, реализующего vectorcall, используйте функцию API вызова, как и любой другой вызываемый объект. PyObject_Vectorcall() обычно будет наиболее эффективной.
Управление рекурсией
При использовании tp_call вызываемые объекты не должны беспокоиться о рекурсии: CPython использует Py_EnterRecursiveCall() и Py_LeaveRecursiveCall() для вызовов, выполненных с помощью tp_call.
В целях повышения эффективности этого не происходит при вызовах, выполненных с использованием vectorcall: вызываемый объект должен использовать Py_EnterRecursiveCall и Py_LeaveRecursiveCall, если это необходимо.
API поддержки Vectorcall
-
Py_ssize_t PyVectorcall_NARGS(size_t nargsf) -
Часть Стабильной ABI с версии 3.12.
На основе аргумента 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.9.
-
PyObject *PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *dict) -
Часть Стабильной ABI с версии 3.12.
Вызывает
vectorcallfuncвызываемого объекта callable с позиционными и именованными аргументами, заданными в кортеже и словаре соответственно.Это специализированная функция, предназначенная для размещения в слоте
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 callable с аргументами, заданными кортежем args, и именованными аргументами, заданными словарем kwargs.
args не должен быть NULL; используйте пустой кортеж, если аргументы не нужны. Если именованные аргументы не нужны, kwargs может быть NULL.
Возвращает результат вызова при успехе или вызывает исключение и возвращает NULL при ошибке.
Это эквивалент выражению Python:
callable(*args, **kwargs).
-
PyObject *PyObject_CallNoArgs(PyObject *callable) -
Значение возврата: новая ссылка. Часть Стабильной ABI с версии 3.10.
Вызов вызываемого объекта Python callable без аргументов. Это наиболее эффективный способ вызова вызываемого объекта Python без аргументов.
Возвращает результат вызова при успехе или вызывает исключение и возвращает NULL при ошибке.
Добавлена в версии 3.9.
-
PyObject *PyObject_CallOneArg(PyObject *callable, PyObject *arg) -
Значение возврата: новая ссылка.
Вызов вызываемого объекта Python callable с ровно 1 позиционным аргументом arg и без именованных аргументов.
Возвращает результат вызова при успехе или вызывает исключение и возвращает NULL при ошибке.
Добавлена в версии 3.9.
-
PyObject *PyObject_CallObject(PyObject *callable, PyObject *args) -
Значение возврата: новая ссылка. Часть Стабильной ABI.
Вызов вызываемого объекта Python callable с аргументами, заданными кортежем args. Если аргументы не нужны, то args может быть NULL.
Возвращает результат вызова при успехе или вызывает исключение и возвращает NULL при ошибке.
Это эквивалент выражению Python:
callable(*args).
-
PyObject *PyObject_CallFunction(PyObject *callable, const char *format, ...) -
Значение возврата: новая ссылка. Часть Стабильной ABI.
Вызов вызываемого объекта 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, ...) -
Значение возврата: новая ссылка. Часть Стабильной ABI.
Вызов метода с именем name объекта obj с переменным числом аргументов C. Аргументы C описываются строкой формата в стиле
Py_BuildValue(), которая должна генерировать кортеж.Формат может быть NULL, что указывает на отсутствие аргументов.
Возвращает результат вызова при успехе или вызывает исключение и возвращает NULL при ошибке.
Это эквивалент выражению Python:
obj.name(arg1, arg2, ...).Обратите внимание, что если вы передаете только PyObject* аргументы,
PyObject_CallMethodObjArgs()— более быстрый вариант.Изменено в версии 3.4: Типы name и формат были изменены с
char *.
-
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) -
Часть Стабильной ABI начиная с версии 3.12.
Вызов вызываемого объекта Python callable. Аргументы такие же, как и для
vectorcallfunc. Если callable поддерживает vectorcall, это напрямую вызывает функцию vectorcall, хранящуюся в callable.Возвращает результат вызова при успехе или поднимает исключение и возвращает 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) -
Часть Стабильной ABI начиная с версии 3.12.
Вызов метода, используя соглашение о вызове 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–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/c-api/call.html