Протокол вызова
CPython поддерживает два разных протокола вызова: tp_call и vectorcall.
Протокол tp_call
Экземпляры классов, задающих tp_call, являются вызываемыми. Сигнатура слота:
PyObject *tp_call(PyObject *callable, PyObject *args, PyObject *kwargs);
Вызов выполняется с использованием кортежа позиционных аргументов и словаря именованных аргументов, как и в callable(*args, **kwargs) в коде Python. args должен быть ненулевым (если аргументов нет, используйте пустой кортеж), но 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().
Примечание
В 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) -
Входит в стабильный 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. Чтобы свести количество преобразований к минимуму, выбирайте функцию, формат которой лучше всего соответствует имеющимся у вас данным.
В следующей таблице перечислены доступные функции; подробную информацию см. в документации к каждой из них.
Функция | вызываемый объект | args | kwargs |
|---|---|---|---|
| кортеж | словарь/ | |
| — | — | |
| 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 ровно с одним позиционным аргументом 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: Тип format изменён с
char *.
-
PyObject *PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...) -
Возвращаемое значение: новая ссылка.Входит в стабильный ABI.
Вызывает метод объекта obj с именем name, передавая переменное число аргументов C. Аргументы C задаются строкой формата
Py_BuildValue(), которая должна создавать кортеж.Формат может быть равен NULL, что означает отсутствие аргументов.
При успешном выполнении возвращает результат вызова, а при ошибке вызывает исключение и возвращает NULL.
Эквивалентное выражение Python:
obj.name(arg1, arg2, ...).Если передаются только аргументы типа PyObject*, более быстрой альтернативой будет
PyObject_CallMethodObjArgs().Изменено в версии 3.4: Типы name и format изменены с
char *.
-
PyObject *PyObject_CallFunctionObjArgs(PyObject *callable, ...) -
Возвращаемое значение: новая ссылка.Входит в стабильный ABI.
Вызывает вызываемый объект Python callable с переменным числом аргументов типа PyObject*. Аргументы передаются как переменное число параметров, за которыми следует NULL.
При успешном выполнении возвращает результат вызова, а при ошибке вызывает исключение и возвращает NULL.
Эквивалентное выражение Python:
callable(arg1, arg2, ...).
-
PyObject *PyObject_CallMethodObjArgs(PyObject *obj, PyObject *name, ...) -
Возвращаемое значение: новая ссылка.Входит в стабильный ABI.
Вызывает метод объекта Python obj, имя которого задано в name в виде строкового объекта Python. Метод вызывается с переменным числом аргументов типа PyObject*. Аргументы передаются как переменное число параметров, за которыми следует NULL.
При успешном выполнении возвращает результат вызова, а при ошибке вызывает исключение и возвращает NULL.
-
PyObject *PyObject_CallMethodNoArgs(PyObject *obj, PyObject *name) -
Вызывает метод объекта Python obj без аргументов; имя метода задано в name в виде строкового объекта Python.
При успешном выполнении возвращает результат вызова, а при ошибке вызывает исключение и возвращает NULL.
Добавлено в версии 3.9.
-
PyObject *PyObject_CallMethodOneArg(PyObject *obj, PyObject *name, PyObject *arg) -
Вызывает метод объекта Python obj с одним позиционным аргументом arg; имя метода задано в name в виде строкового объекта Python.
При успешном выполнении возвращает результат вызова, а при ошибке вызывает исключение и возвращает 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.12/c-api/call.html