ЧАВО по расширению/встраиванию
- Можно ли создавать свои функции в C?
- Можно ли создавать свои функции в C++?
- Написание на C сложно; есть ли альтернативы?
- Как выполнить произвольные операторы Python из C?
- Как оценить произвольное выражение Python из C?
- Как извлечь значения C из объекта Python?
- Как использовать Py_BuildValue() для создания кортежа произвольной длины?
- Как вызвать метод объекта из C?
- Как перехватить вывод из PyErr_Print() (или чего-либо, что выводит в stdout/stderr)?
- Как получить доступ к модулю, написанному на Python, из C?
- Как взаимодействовать с объектами C++ из Python?
- Я добавил модуль с помощью файла Setup, но make завершается ошибкой; почему?
- Как отладить расширение?
- Я хочу скомпилировать модуль Python на моей Linux-системе, но некоторые файлы отсутствуют. Почему?
- Как отличить «неполный ввод» от «неправильного ввода»?
- Как найти неопределенные символы g++ __builtin_new или __pure_virtual?
- Можно ли создать класс объекта с методами, реализованными на C и других на Python (например, через наследование)?
Можно ли создавать свои функции в C?
Да, вы можете создавать встроенные модули, содержащие функции, переменные, исключения и даже новые типы на языке C. Это описано в документе Расширение и встраивание интерпретатора Python.
Большинство учебников по Python среднего или продвинутого уровня также охватывают эту тему.
Можно ли создавать свои функции в C++?
Да, используя возможности совместимости C в C++. Разместите extern "C" {
... } вокруг файлов заголовков Python и поместите extern "C" перед каждой функцией, которая будет вызываться интерпретатором Python. Глобальные или статические C++ объекты со конструкторами, вероятно, не являются хорошей идеей.
Написание на C сложно; есть ли альтернативы?
Есть несколько альтернатив написанию собственных расширений C, в зависимости от того, что вы пытаетесь сделать.
Cython и его аналог Pyrex — это компиляторы, которые принимают слегка изменённую форму Python и генерируют соответствующий код C. Cython и Pyrex позволяют писать расширение, не изучая API C Python.
Если вам нужно взаимодействовать с какой-либо библиотекой C или C++, для которой в настоящее время нет расширения Python, вы можете попробовать обернуть типы данных и функции библиотеки с помощью инструмента, такого как SWIG. SIP, CXX Boost или Weave также являются альтернативами для обертывания библиотек C++.
Как выполнить произвольные операторы Python из C?
Функция высокого уровня для этого — PyRun_SimpleString(), которая принимает один строковый аргумент, который будет выполняться в контексте модуля __main__ и возвращает 0 при успехе и -1 при возникновении исключения (включая SyntaxError). Если вам нужен больший контроль, используйте PyRun_String(); см. исходный код PyRun_SimpleString() в Python/pythonrun.c.
Как оценить произвольное выражение Python из C?
Вызовите функцию PyRun_String() из предыдущего вопроса с начальным символом Py_eval_input; она анализирует выражение, вычисляет его и возвращает его значение.
Как извлечь значения C из объекта Python?
Это зависит от типа объекта. Если это кортеж, PyTuple_Size() возвращает его длину, а PyTuple_GetItem() — элемент по указанному индексу. У списков есть аналогичные функции: PyList_Size() и PyList_GetItem().
Для байтовых объектов PyBytes_Size() возвращает его длину, а PyBytes_AsStringAndSize() предоставляет указатель на его значение и длину. Обратите внимание, что объекты Python bytes могут содержать нулевые байты, поэтому C’s strlen() не следует использовать.
Чтобы проверить тип объекта, сначала убедитесь, что он не NULL, а затем используйте PyBytes_Check(), PyTuple_Check(), PyList_Check() и т. д.
Также существует интерфейс высокого уровня для объектов Python, который предоставляется так называемым «абстрактным» интерфейсом — см. Include/abstract.h для получения дополнительной информации. Он позволяет взаимодействовать с любым типом последовательности Python с помощью вызовов, таких как PySequence_Length(), PySequence_GetItem() и т. д., а также многие другие полезные протоколы, такие как числа (PyNumber_Index() и др.) и отображения в API PyMapping.
Как использовать Py_BuildValue() для создания кортежа произвольной длины?
Вы не можете. Используйте PyTuple_Pack() вместо этого.
Как вызвать метод объекта из C?
Функция PyObject_CallMethod() может использоваться для вызова произвольного метода объекта. Параметрами являются объект, имя вызываемого метода, строка формата, подобная той, что используется с Py_BuildValue(), и значения аргументов:
PyObject *
PyObject_CallMethod(PyObject *object, const char *method_name,
const char *arg_format, ...);
Это работает для любого объекта, имеющего методы — встроенные или определённые пользователем. Вы несете ответственность за последующий вызов Py_DECREF() для возвращаемого значения.
Например, чтобы вызвать метод «seek» объекта файла с аргументами 10, 0 (предполагая, что указатель на объект файла «f»):
res = PyObject_CallMethod(f, "seek", "(ii)", 10, 0);
if (res == NULL) {
... an exception occurred ...
}
else {
Py_DECREF(res);
}
Обратите внимание, что, поскольку PyObject_CallObject() всегда требует кортежа для списка аргументов, для вызова функции без аргументов передайте «()», а для вызова функции с одним аргументом поместите аргумент в скобки, например, «(i)».
Как перехватить вывод из PyErr_Print() (или чего-либо, что выводит в stdout/stderr)?
В коде Python определите объект, поддерживающий метод write(). Присвойте этот объект sys.stdout и sys.stderr. Вызовите print_error или просто позвольте стандартной механике отслеживания работать. Затем вывод попадёт туда, куда направляет ваш метод write().
Самый простой способ сделать это — использовать класс io.StringIO:
>>> import io, sys
>>> sys.stdout = io.StringIO()
>>> print('foo')
>>> print('hello world!')
>>> sys.stderr.write(sys.stdout.getvalue())
foo
hello world!
Пользовательский объект для того же будет выглядеть так:
>>> import io, sys
>>> class StdoutCatcher(io.TextIOBase):
... def __init__(self):
... self.data = []
... def write(self, stuff):
... self.data.append(stuff)
...
>>> import sys
>>> sys.stdout = StdoutCatcher()
>>> print('foo')
>>> print('hello world!')
>>> sys.stderr.write(''.join(sys.stdout.data))
foo
hello world!
Как получить доступ к модулю, написанному на Python, из C?
Вы можете получить указатель на объект модуля следующим образом:
module = PyImport_ImportModule("<modulename>");
Если модуль еще не импортирован (т.е. он еще не присутствует в sys.modules), это инициализирует модуль; в противном случае он просто возвращает значение sys.modules["<modulename>"]. Обратите внимание, что он не добавляет модуль в какое-либо пространство имен — он только гарантирует, что он был инициализирован и сохранен в sys.modules.
Затем вы можете получить доступ к атрибутам модуля (т.е. к любому имени, определенному в модуле) следующим образом:
attr = PyObject_GetAttrString(module, "<attrname>");
Вызов PyObject_SetAttrString() для присваивания переменным в модуле также работает.
Как интегрировать объекты C++ в Python?
В зависимости от ваших требований, существует множество подходов. Для ручного взаимодействия начните с чтения документа «Расширение и встраивание». Понимайте, что для системы выполнения Python практически нет большой разницы между C и C++ — поэтому стратегия создания нового типа Python вокруг типа структуры C (указатель) также будет работать для объектов C++.
Для библиотек C++ см. Сложно ли писать на C? Есть ли альтернативы?.
Я добавил модуль с помощью файла Setup, но make завершается ошибкой; почему?
Файл Setup должен заканчиваться новой строкой. Если новой строки нет, процесс сборки завершается ошибкой. (Для исправления этого требуется немного уродливая настройка скрипта оболочки, и эта ошибка настолько незначительна, что, кажется, не стоит усилий.)
Как отладить расширение?
При использовании GDB с динамически загружаемыми расширениями вы не можете установить точку останова в своем расширении до тех пор, пока оно не загружено.
В вашем .gdbinit файле (или интерактивно) добавьте команду:
br _PyImport_LoadDynamicModule
Затем, когда вы запустите GDB:
$ gdb /local/bin/python gdb) run myscript.py gdb) continue # repeat until your extension is loaded gdb) finish # so that your extension is loaded gdb) br myfunction.c:50 gdb) continue
Я хочу скомпилировать модуль Python на моей Linux-системе, но некоторые файлы отсутствуют. Почему?
В большинстве упакованных версий Python отсутствуют некоторые файлы, необходимые для компиляции расширений Python.
Для Red Hat установите RPM-пакет python3-devel, чтобы получить необходимые файлы.
Для Debian выполните apt-get install python3-dev.
Как отличить «неполный ввод» от «неправильного ввода»?
Иногда вам нужно смоделировать поведение интерактивного интерпретатора Python, где он предлагает продолжение при неполном вводе (например, вы набрали начало оператора «if» или не закрыли скобки или тройные строковые кавычки), но сразу же сообщает о синтаксической ошибке при некорректном вводе.
В Python вы можете использовать модуль codeop, который достаточно точно моделирует поведение парсера. Например, IDLE использует его.
Самый простой способ сделать это в C — вызвать PyRun_InteractiveLoop() (возможно, в отдельном потоке) и позволить интерпретатору Python обрабатывать ввод за вас. Вы также можете установить PyOS_ReadlineFunctionPointer() на указание вашей пользовательской функции ввода. См. Modules/readline.c и Parser/myreadline.c для дополнительных подсказок.
Как найти неопределённые символы g++ __builtin_new или __pure_virtual?
Для динамической загрузки модулей расширений g++, необходимо перекомпилировать Python, перелинковать его с помощью g++ (изменить LINKCC в файле Makefile модулей Python) и скомпилировать ваш модуль расширения с помощью g++ (например, g++ -shared -o mymodule.so mymodule.o).
Можно ли создать класс объекта с некоторыми методами, реализованными на C, и другими на Python (например, через наследование)?
Да, вы можете наследовать от встроенных классов, таких как int, list, dict и т.д.
Библиотека Boost Python (BPL, https://www.boost.org/libs/python/doc/index.html) предоставляет способ сделать это из C++ (т.е. вы можете наследовать от класса расширения, написанного на C++, с использованием BPL).
© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/faq/extending.html