Spec-Zone.ru › Python 3.14

Протокол вызова

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. Чтобы свести к минимуму количество преобразований, выберите функцию, формат которой лучше всего соответствует доступным вам данным.

В следующей таблице приведены доступные функции; подробности см. в документации к каждой из них.

Функция

вызываемый объект

аргументы

именованные аргументы

PyObject_Call()

PyObject *

кортеж

словарь/NULL

PyObject_CallNoArgs()

PyObject *

—

—

PyObject_CallOneArg()

PyObject *

1 объект

—

PyObject_CallObject()

PyObject *

кортеж/NULL

—

PyObject_CallFunction()

PyObject *

формат

—

PyObject_CallMethod()

объект + char*

формат

—

PyObject_CallFunctionObjArgs()

PyObject *

переменное число аргументов

—

PyObject_CallMethodObjArgs()

объект + имя

переменное число аргументов

—

PyObject_CallMethodNoArgs()

объект + имя

—

—

PyObject_CallMethodOneArg()

объект + имя

1 объект

—

PyObject_Vectorcall()

PyObject *

vectorcall

vectorcall

PyObject_VectorcallDict()

PyObject *

vectorcall

словарь/NULL

PyObject_VectorcallMethod()

аргумент + имя

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, имя которого задано объектом-строкой 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)
Входит в стабильный ABI начиная с версии 3.12.

Вызывает вызываемый объект Python callable. Аргументы совпадают с аргументами vectorcallfunc. Если callable поддерживает vectorcall, функция напрямую вызывает функцию vectorcall, хранящуюся в callable.

При успешном выполнении возвращает результат вызова, а при ошибке вызывает исключение и возвращает NULL.

Добавлено в версии 3.8: под именем _PyObject_Vectorcall

Изменено в версии 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 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.14/c-api/call.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API