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

CPython поддерживает два различных протокола вызова: tp_call и vector call.

Протокол tp_call

Экземпляры классов, которые задают tp_call, доступны для вызова. Сигнатура слота - это:

PyObject *tp_call(PyObject *callable, PyObject *args, PyObject *kwargs);

Вызов выполняется с использованием кортежа для позиционных аргументов и dict для ключевых аргументов, аналогично callable(*args, **kwargs) в коде Python. args должно быть ненулевым (используйте пустой кортеж, если нет аргументов), но kwargs может быть NULL, если нет аргументов ключевого слова.

Это соглашение используется не только tp_call: tp_new и tp_init также передают аргументы таким образом.

Чтобы вызвать объект, используйте PyObject_Call() или другой call API.

Протокол векторных вызовов

Добавлено в версии 3.9.

Протокол vector call protocol был представлен в PEP 590 в качестве дополнительного протокола для повышения эффективности звонков.

Как показывает практика, CPython предпочтет вызов vector для внутренних вызовов, если вызываемый объект поддерживает его. Однако это не является жестким правилом. Кроме того, некоторые сторонние расширения используют tp_call напрямую (вместо использования PyObject_Call()). Следовательно, класс, поддерживающий vectorcall, также должен реализовывать tp_call. Более того, вызываемый объект должен вести себя одинаково независимо от того, какой протокол используется. Рекомендуемый способ добиться этого - установить для параметра tp_call значение PyVectorcall_Call(). Это следует повторить:

Предупреждение

Класс, поддерживающий вызов vector **, должен ** также реализовывать tp_call с той же семантикой.

Класс не должен реализовывать вызов vector, если это будет медленнее, чем tp_call. Например, если вызываемому объекту все равно нужно преобразовать аргументы в кортеж args и kwargs dict, тогда нет смысла реализовывать vectorcall.

Классы могут реализовать протокол вызова vector, включив флаг Py_TPFLAGS_HAVE_VECTORCALL и установив значение tp_vectorcall_offset для смещения внутри структуры объекта, где отображается vectorcallfunc. Это указатель на функцию со следующей сигнатурой:

typedef PyObject *(*vectorcallfunc)(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames)
  • вызываемый - это вызываемый объект.

  • args - это массив на языке Си, состоящий из позиционных аргументов, за которыми следует

    значения ключевого слова arguments. Это может быть NULL, если аргументов нет.

  • nargsf - это количество позиционных аргументов плюс, возможно,

    :флаг c:macro:PY_VECTORCALL_ARGUMENTS_OFFSET. Чтобы получить фактическое количество позиционных аргументов из nargsf, используйте PyVectorcall_NARGS().

  • kwnames - это кортеж, содержащий имена аргументов ключевого слова;

    другими словами, ключи kwargs dict. Эти имена должны быть строками (экземплярами str или подкласса) и они должны быть уникальными. Если аргументов ключевого слова нет, то вместо kwnames может быть NULL.

PY_VECTORCALL_ARGUMENTS_OFFSET

Если этот флаг установлен в аргументе векторного вызова nargsf, вызываемому объекту разрешается временно изменять args[-1]. Другими словами, args указывает на аргумент 1 (а не 0) в выделенном векторе. Вызываемый объект должен восстановить значение args[-1] перед возвратом.

Для PyObject_VectorcallMethod() этот флаг вместо этого означает, что args[0] может быть изменен.

Всякий раз, когда они могут сделать это дешево (без дополнительного выделения ресурсов), вызывающим объектам рекомендуется использовать PY_VECTORCALL_ARGUMENTS_OFFSET. Это позволит вызываемым объектам, таким как связанные методы, выполнять свои последующие вызовы (которые включают в себя добавленный аргумент self) очень эффективно.

Добавлено в версии 3.8.

Чтобы вызвать объект, реализующий вызов vector, используйте функцию call 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 вызываемым абонентам не нужно беспокоиться о recursion: CPython использует Py_EnterRecursiveCall() и Py_LeaveRecursiveCall() для вызовов, выполненных с использованием tp_call.

Для повышения эффективности это не относится к вызовам, выполняемым с помощью vectorcall: вызываемый объект должен использовать Py_EnterRecursiveCall и Py_LeaveRecursiveCall, если это необходимо.

API поддержки векторных вызовов

Py_ssize_t PyVectorcall_NARGS(size_t nargsf)

При заданном аргументе vector call nargsf возвращает фактическое количество аргументов. В настоящее время эквивалентно:

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)

Однако для обеспечения возможности будущих расширений следует использовать функцию PyVectorcall_NARGS.

Добавлено в версии 3.8.

vectorcallfunc PyVectorcall_Function(PyObject *op)

Если op не поддерживает протокол вызова vector (либо потому, что не поддерживает тип, либо потому, что не поддерживает конкретный экземпляр), верните NULL. В противном случае верните указатель на функцию vectorcall, сохраненный в op. Эта функция никогда не вызывает исключения.

В основном это полезно для проверки того, поддерживает ли op вызов вектора, что можно сделать, установив флажок PyVectorcall_Function(op) != NULL.

Добавлено в версии 3.9.

PyObject *PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *dict)

Вызовите callable’s vectorcallfunc с аргументами позиции и ключевого слова, заданными в виде кортежа и dict соответственно.

Это специализированная функция, предназначенная для размещения в слоте 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()

obj + char*

формат

PyObject_CallFunctionObjArgs()

PyObject *

вариативный

PyObject_CallMethodObjArgs()

объект + имя

вариативный

PyObject_CallMethodNoArgs()

объект + имя

PyObject_CallMethodOneArg()

объект + имя

1 объект

PyObject_Vectorcall()

PyObject *

векторный вызов

векторный вызов

PyObject_VectorcallDict()

PyObject *

векторный вызов

диктовать/NULL

PyObject_VectorcallMethod()

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

векторный вызов

векторный вызов

PyObject *PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
Возвращаемое значение: Новая ссылка. Part of the Стабильный ABI.

Вызовите вызываемый объект Python callable с аргументами, заданными кортежем args, и именованными аргументами, заданными словарем kwargs.

args не должны быть NULL; используйте пустой кортеж, если аргументы не нужны. Если именованные аргументы не нужны, kwargs может быть NULL.

Возвращает результат вызова в случае успеха или вызывает исключение и возвращает NULL в случае сбоя.

Это эквивалент выражения Python: callable(*args, **kwargs).

PyObject *PyObject_CallNoArgs(PyObject *callable)
Возвращаемое значение: Новая ссылка. Part of the Стабильный ABI since version 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)
Возвращаемое значение: Новая ссылка. Part of the Стабильный ABI.

Вызовите вызываемый объект Python callable с аргументами, указанными в кортеже args. Если аргументы не нужны, то args может быть NULL.

Возвращает результат вызова в случае успеха или вызывает исключение и возвращает NULL в случае сбоя.

Это эквивалент выражения Python: callable(*args).

PyObject *PyObject_CallFunction(PyObject *callable, const char *format, ...)
Возвращаемое значение: Новая ссылка. Part of the Стабильный 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, ...)
Возвращаемое значение: Новая ссылка. Part of the Стабильный ABI.

Вызовите метод с именем name объекта obj с переменным числом аргументов на языке C. Аргументы на языке C описываются строкой формата Py_BuildValue(), которая должна привести к созданию кортежа.

Формат может быть NULL, что указывает на отсутствие аргументов.

Возвращает результат вызова в случае успеха или вызывает исключение и возвращает NULL в случае сбоя.

Это эквивалент выражения Python: obj.name(arg1, arg2, ...).

Обратите внимание, что если вы передаете только PyObject* аргументы, то PyObject_CallMethodObjArgs() является более быстрой альтернативой.

Изменено в версии 3.4: Типы имя и формат были изменены с char *.

PyObject *PyObject_CallFunctionObjArgs(PyObject *callable, ...)
Возвращаемое значение: Новая ссылка. Part of the Стабильный ABI.

Вызовите вызываемый объект Python callable с переменным количеством аргументов PyObject*. Аргументы представлены в виде переменного количества параметров, за которыми следует NULL.

Возвращает результат вызова в случае успеха или вызывает исключение и возвращает NULL в случае сбоя.

Это эквивалент выражения Python: callable(arg1, arg2, ...).

PyObject *PyObject_CallMethodObjArgs(PyObject *obj, PyObject *name, ...)
Возвращаемое значение: Новая ссылка. Part of the Стабильный 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 callable. Аргументы те же, что и для vectorcallfunc. Если callable поддерживает 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)

Вызовите метод, используя соглашение о вызове vector call. Имя метода задается в виде строки Python name. Объект, метод которого вызывается, называется args[0], а массив args, начинающийся с args[1], представляет аргументы вызова. Должен быть хотя бы один позиционный аргумент. nargsf - это количество позиционных аргументов, включая args[0], плюс PY_VECTORCALL_ARGUMENTS_OFFSET, если значение args[0] может быть временно изменено. Аргументы ключевого слова могут передаваться точно так же, как в PyObject_Vectorcall().

Если у объекта есть функция Py_TPFLAGS_METHOD_DESCRIPTOR, то будет вызван несвязанный метод object с полным вектором args в качестве аргументов.

Возвращает результат вызова в случае успеха или вызывает исключение и возвращает NULL в случае сбоя.

Добавлено в версии 3.9.

API поддержки вызовов

int PyCallable_Check(PyObject *o)
Part of the Стабильный ABI.

Определите, доступен ли объект o для вызова. Верните 1, если объект доступен для вызова, и 0 в противном случае. Эта функция всегда выполняется успешно.

Вернуться на верх