Содержание страницы
Протокол вызова¶Call Protocol
CPython поддерживает два протокола вызова: tp_call и vectorcall.
tp_call¶The tp_call Protocol
Экземпляры классов, в которых задан 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¶The Vectorcall Protocol
Новое в версии 3.9.
Протокол vectorcall был представлен в PEP 590 как дополнительный протокол для повышения эффективности вызовов.
Как правило, CPython предпочитает vectorcall для внутренних вызовов,
если вызываемый объект его поддерживает. Однако это не жёсткое правило.
Кроме того, некоторые сторонние расширения используют tp_call напрямую
(вместо PyObject_Call()).
Поэтому класс, поддерживающий vectorcall, должен также реализовывать
tp_call.
Более того, вызываемый объект должен вести себя одинаково
независимо от используемого протокола.
Рекомендуемый способ добиться этого – задать
tp_call равным PyVectorcall_Call().
Это стоит повторить:
Предупреждение
Класс, поддерживающий vectorcall, должен также реализовывать
tp_call с той же семантикой.
Класс не должен реализовывать 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)¶
callable – это вызываемый объект.
- args – это массив C, состоящий из позиционных аргументов, за которыми следуют
значения именованных аргументов. Может быть NULL, если аргументов нет.
- nargsf – это количество позиционных аргументов плюс, возможно,
флаг
PY_VECTORCALL_ARGUMENTS_OFFSET. Чтобы получить фактическое количество позиционных аргументов из nargsf, используйтеPyVectorcall_NARGS().
- kwnames – это кортеж, содержащий имена именованных аргументов;
другими словами, ключи словаря kwargs. Эти имена должны быть строками (экземплярами
strили подкласса) и они должны быть уникальными. Если именованных аргументов нет, то kwnames может быть NULL.
-
PY_VECTORCALL_ARGUMENTS_OFFSET¶ Если этот флаг установлен в аргументе vectorcall nargsf, вызываемой стороне разрешается временно изменить
args[-1]. Иными словами, args указывает на аргумент 1 (а не 0) в выделенном векторе. Вызываемая сторона должна восстановить значениеargs[-1]перед возвратом.Для
PyObject_VectorcallMethod()этот флаг, напротив, означает, чтоargs[0]может быть изменён.Если это можно сделать дёшево (без дополнительных выделений памяти), вызывающим сторонам рекомендуется использовать
PY_VECTORCALL_ARGUMENTS_OFFSET. Это позволит таким вызываемым объектам, как связанные методы, выполнять последующие вызовы (которые включают добавленный аргумент self) очень эффективно.
Для вызова объекта, реализующего vectorcall, используйте функцию 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.
Старые имена по-прежнему определены как псевдонимы новых имен без подчеркивания.
Управление рекурсией¶Recursion Control
При использовании tp_call вызываемым сторонам не нужно беспокоиться о
рекурсии: CPython использует
Py_EnterRecursiveCall() и Py_LeaveRecursiveCall()
для вызовов, выполненных с помощью tp_call.
Для эффективности это не относится к вызовам, выполненным с помощью vectorcall: вызываемая сторона должна использовать Py_EnterRecursiveCall и Py_LeaveRecursiveCall, если это необходимо.
API поддержки Vectorcall¶Vectorcall Support API
-
Py_ssize_t
PyVectorcall_NARGS(size_t nargsf)¶ Получив аргумент vectorcall 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.8.
-
PyObject *
PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *dict)¶ Вызывает
vectorcallfuncобъекта callable с позиционными и именованными аргументами, заданными в виде кортежа и словаря соответственно.Это специализированная функция, предназначенная для размещения в слоте
tp_callили использования в реализацииtp_call. Она не проверяет флагPy_TPFLAGS_HAVE_VECTORCALLи не обращается кtp_callв качестве запасного варианта.Новое в версии 3.8.
API вызова объектов¶Object Calling API
Доступны различные функции для вызова объекта Python. Каждая преобразует свои аргументы в соглашение, поддерживаемое вызываемым объектом – tp_call или vectorcall. Чтобы выполнить как можно меньше преобразований, выбирайте ту, которая лучше всего подходит под формат имеющихся у вас данных.
В следующей таблице приведены доступные функции; подробнее см. в документации для каждой из них.
Функция |
вызываемый |
аргументы |
именованные аргументы |
|---|---|---|---|
|
кортеж |
словарь/ |
|
|
– |
– |
|
|
1 объект |
– |
|
|
кортеж/ |
– |
|
|
формат |
– |
|
объект + |
формат |
– |
|
|
вариативный |
– |
|
объект + имя |
вариативный |
– |
|
объект + имя |
– |
– |
|
объект + имя |
1 объект |
– |
|
|
vectorcall |
vectorcall |
|
|
vectorcall |
словарь/ |
|
аргумент + имя |
vectorcall |
vectorcall |
-
PyObject *
PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)¶ - Возвращаемое значение: новая ссылка. Часть Stable ABI.
Вызывает вызываемый объект Python callable с аргументами, заданными кортежем args, и именованными аргументами, заданными словарём kwargs.
args не должен быть NULL; используйте пустой кортеж, если аргументы не нужны. Если именованные аргументы не нужны, kwargs может быть NULL.
Возвращает результат вызова при успехе или возбуждает исключение и возвращает NULL при неудаче.
Это эквивалент выражения Python:
callable(*args, **kwargs).
-
PyObject *
PyObject_CallNoArgs(PyObject *callable)¶ - Часть Stable 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)¶ - Возвращаемое значение: новая ссылка. Часть Stable ABI.
Вызывает вызываемый объект Python callable с аргументами, заданными кортежем args. Если аргументы не нужны, args может быть NULL.
Возвращает результат вызова при успехе или возбуждает исключение и возвращает NULL при неудаче.
Это эквивалент выражения Python:
callable(*args).
-
PyObject *
PyObject_CallFunction(PyObject *callable, const char *format, ...)¶ - Возвращаемое значение: новая ссылка. Часть Stable 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, ...)¶ - Возвращаемое значение: новая ссылка. Часть Stable ABI.
Вызывает метод с именем name объекта obj с переменным числом аргументов C. Аргументы C описываются строкой формата
Py_BuildValue(), которая должна порождать кортеж.Формат может быть NULL, что означает, что аргументы не предоставлены.
Возвращает результат вызова при успехе или возбуждает исключение и возвращает NULL при неудаче.
Это эквивалент выражения Python:
obj.name(arg1, arg2, ...).Обратите внимание: если передаются только аргументы
PyObject*, тоPyObject_CallMethodObjArgs()– более быстрая альтернатива.Изменено в версии 3.4: Типы name и format были изменены с
char *.
-
PyObject *
PyObject_CallFunctionObjArgs(PyObject *callable, ...)¶ - Возвращаемое значение: новая ссылка. Часть Stable ABI.
Вызов вызываемого объекта Python callable с переменным числом аргументов
PyObject*. Аргументы передаются как переменное число параметров, после которых следует NULL.Возвращает результат вызова при успехе или возбуждает исключение и возвращает NULL при неудаче.
Это эквивалент выражения Python:
callable(arg1, arg2, ...).
-
PyObject *
PyObject_CallMethodObjArgs(PyObject *obj, PyObject *name, ...)¶ - Возвращаемое значение: новая ссылка. Часть Stable 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, то эта функция напрямую вызывает функцию 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)¶ Вызывает метод, используя соглашение о вызове 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 поддержки вызова¶Call Support API
-
int
PyCallable_Check(PyObject *o)¶ - Часть Stable ABI.
Определяет, является ли объект o вызываемым. Возвращает
1, если объект вызываем, и0в противном случае. Эта функция всегда завершается успешно.