Spec-Zone.ru › Python 3.12

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

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() обычно будет наиболее эффективной.

Примечание

В 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, вернуть фактическое количество аргументов. В настоящее время эквивалентно:

(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 ровно с 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* args, PyObject_CallFunctionObjArgs() является более быстрой альтернативой.

Изменено в версии 3.4: Тип format был изменен с 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* args, PyObject_CallMethodObjArgs() является более быстрой альтернативой.

Изменено в версии 3.4: Типы name и format были изменены с 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.12/c-api/call.html

Spec-Zone.ru

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