Перезапуск интерпретатора Python с использованием Python C API

У меня есть приложение C++/Qt, в котором я запускаю сеанс интерпретатора Python в процессе основного приложения. Я создал «консоль Python» в виде виджета QPlainTextEdit, который обрабатывает ввод и вывод для интерпретатора с помощью API Python C. Смысл всего этого в том, что Python будет иметь прямой доступ к данным, которые я храню внутри основного приложения. Все хорошо, за исключением того, что я хочу иметь возможность завершить текущий сеанс интерпретатора и перезапустить его, не выходя из основного приложения.

В настоящее время я пробую очевидный способ:

Py_Initialize();
// Run the main session...
Py_FinalizeEx();

// Restart the session
Py_Initialize();

Судя по другим сообщениям и документации Python, могут возникнуть проблемы с перезагрузкой определенных модулей после завершения работы интерпретатора из-за утечек памяти. В моем случае это похоже на правду: повторный импорт определенных модулей (например, «numpy»), но не других (например, «sys») вызовет исключение и завершится ошибкой.

Существует ли хорошая стратегия обхода, позволяющая перезапустить интерпретатор без этих проблем? Например, если я создаю субинтерпретатор, возникнут ли при его завершении и перезапуске нового субинтерпретатора те же проблемы, что и у меня? Альтернатива, которой я пытался избежать, — это запуск Python вне процесса, что, я думаю, позволило бы мне перезапустить его, по сути убив процесс и запустив новый. Любые советы по стратегии будут высоко оценены.

Почему необходимо завершить и повторно инициализировать? Разве вы не можете инициализировать один раз и завершить только при выходе?

wohlstad 07.05.2024 07:11

Почему вы хотите завершить текущий сеанс переводчика и перезапустить его? Кажется, это XY проблема.

Chukwujiobi Canon 07.05.2024 08:38

У вас есть API подинтерпретаторов, если вы хотите, чтобы в вашем приложении было несколько интерпретаторов, их можно безопасно создавать и уничтожать.

Ahmed AEK 07.05.2024 09:09

Numpy — это именно тот проблемный дочерний элемент, который нельзя загружать несколько раз в одном процессе.

Botje 07.05.2024 09:12

@ChukwujiobiCanon В идеале у пользователя должна быть возможность изменить среду Python, которую использует основное приложение. Кроме того, основное приложение представляет собой пакет анализа данных, поэтому пользователи уже могут начать новый файл/сеанс анализа из меню «Файл», не выходя из приложения. В этом случае они также ожидают нового сеанса Python.

Ben Murphy-Baum 07.05.2024 17:26

@BenMurphy-Baum, в этом случае запуск Python как внешнего процесса кажется мне лучшим решением.

wohlstad 07.05.2024 17:38
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
6
120
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Из документации Py_FinalizeEx:

Ошибки и предостережения: Уничтожение модулей и объектов в модулях делается в случайном порядке; это может вызвать деструкторы (методы del()) потерпеть неудачу, когда они зависят от других объектов (даже функций) или модулей. Динамически загружаемые модули расширения, загружаемые Python, не выгружен. Небольшие объемы памяти, выделяемые интерпретатором Python не может быть освобожден (если вы обнаружите утечку, сообщите об этом). Память привязана up в циклических ссылках между объектами не освобождается. Немного памяти выделенные модулями расширения не могут быть освобождены. Некоторые расширения могут не работают должным образом, если их процедура инициализации вызывается более чем один раз; это может произойти, если приложение вызывает Py_Initialize() и Py_FinalizeEx() более одного раза.

Особо отметим, что:

Некоторые расширения могут работать неправильно, если их процедура инициализации вызывается более чем один раз; это может произойти, если приложение вызывает Py_Initialize() и Py_FinalizeEx() более одного раза.

(выделено мной)

Понятно, что проект не поддерживает финализацию и повторную инициализацию при попытке.

Поэтому рекомендуется инициализировать движок Python один раз (при запуске процесса или в первый раз, когда он вам понадобится) и завершать его только при выходе (или, по крайней мере, когда вы уверены, что он вам больше не понадобится).

Даже если вы найдете обходной путь, который будет работать в конкретном сценарии, я не думаю, что это хорошая идея, учитывая приведенную выше информацию.

Примечание:
Если у вас есть какие-либо требования, требующие создания новой среды Python для каждого сеанса или операции, лучший подход — запустить Python как внешний процесс.

Другие вопросы по теме