Уведомления

Группа в Telegram: @pythonsu

#1 Окт. 2, 2009 11:01:12

vkornienko
От:
Зарегистрирован: 2009-10-02
Сообщения: 2
Репутация: +  0  -
Профиль   Отправить e-mail  

Py_Initialize in mixed (embeded and extended) mode

Всем привет!
Есть некая архитектура в которую надо вписать расширяемость с помощью скриптов на питоне. В результате пришлось воспользоваться как методом расширения так и методом внедрения питона. Но это все для общего контекста (проблемы).
Итак есть сишное приложени (вернее С++). В основном потоке приложения создаю еще один для питона, и уже в нем выполняю следующий код:

   PyEval_InitThreads();
Py_Initialize(); // <----- здесь поток повисает на ожидании ввода строки из stdin
PyThreadState* mainThreadState = PyEval_SaveThread();

PyGILState_STATE gilState = PyGILState_Ensure();
Py_InitModule ("myModule", myMethods);
char* fileName = (char*)param;
runPyFile (fileName);
PyGILState_Release(gilState);

PyEval_RestoreThread(mainThreadState);
Py_Finalize();
В принципе все работает, удается в дальнейшем нормально общаться с питоном через зарегистрированные функции. НО. При вызове функции Py_Initialize() поток питона повисает на ожидании ввода чего-то из stdin. Если ввести пустую строку (просто нажать Enter), то приложение продолжает свою работу, если ввеси какой-то текст - вылетает.
Собственно вопрос - как заставить питон не ожидать ввода из stdin?



Офлайн

#2 Окт. 2, 2009 19:22:52

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

Py_Initialize in mixed (embeded and extended) mode

Ввод из stdin скорее всего делает какой-нибудь init<module> из ваших embedded modules.
Стандартный питон такой функциональности не имеет, поверьте.

Вижу еще одну проблему: вы вызывает Py_Initialize/Py_Finalize для каждого запуска, так? Или runPyFile делается один раз за время жизни программы?
Дело в том, что Py_Finalize не сможет корректно выгрузить C Extensions. Просто напросто нет такого API. Есть PEP 3121 http://www.python.org/dev/peps/pep-3121/
на это дело, но его еще не реализовали. Так что как минимум память будет теряться, как максимум (для нетривиальных случаев) - ждите краша.



Офлайн

#3 Окт. 3, 2009 00:56:27

vkornienko
От:
Зарегистрирован: 2009-10-02
Сообщения: 2
Репутация: +  0  -
Профиль   Отправить e-mail  

Py_Initialize in mixed (embeded and extended) mode

Спасибо за ответ.
С проблемой разобрался - оказывается был мой косяк. Просто я ожидал ввода в основном потоке, странно почему поток питона повис на этом же вводе. Ну да ладно, в реальных условиях ничего из stdin читать не придется…
А так вообще поток питона запускается один раз… Так что надеюсь описанные выше проблемы меня не каснуться :)



Офлайн

#4 Окт. 11, 2009 12:44:53

chertov
От:
Зарегистрирован: 2009-07-20
Сообщения: 2
Репутация: +  0  -
Профиль   Отправить e-mail  

Py_Initialize in mixed (embeded and extended) mode

Здравствуйте! У меня похожая задача, прошу совета!
Пытаюсь сделать поддержку приложением питоновских скриптов.

На данный момент связал С++ классы с питоном использую SWIG.

Думаю информация будет полезной для сообщества, напишу подробнее о том как использовал SWIG.
Вот простой пример, исходники на С++:

example.hpp

#pragma once
#include <string>

class A
{
public:
A(void);
std::string getStr(void);
};
example.cpp
#include "example.hpp"

A::A(void) { }
std::string A::getStr(void) {
std::string str("Hello, World!");
return str;
}
Для использования SWIG'а пишу example.i
%module example
%{
#include "example.hpp"
%}

%include "std_vector.i"
%include "std_string.i"

%include "example.hpp"
Далее нужно сгенерировать исходники с помощью SWIG и откомпилировать их.
Компилирую с помощью Visual Studio 2009 из командной строки.
Для этого написал bat файл.
:: Запускаю SWIG
"C:\Program Files\SWIG\swigwin-1.3.40\swig.exe" -python -c++ example.i

@echo off
:: Устанавливаю переменные для работы cl.exe
call "C:\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"
:: Собираю исходники в DLL, которую сохраняю с расширением *.pyd
"C:\Program Files\Microsoft Visual Studio 9.0\VC\bin\cl.exe" example_wrap.cxx example.cpp -I "C:\Python26\include" /link /OUT:"_example.pyd" /DLL /LIBPATH:"C:\Python26\libs"

:: Удаляю мусор
rm *.exp
rm *.lib
rm *.obj
rm *_wrap.cxx
rm *.pyc
pause
Теперь если выполнить
>>> import example
>>> x = example.A()
>>> print x.getStr()
Hello, World!
>>>
Как видим все работает!





Далее мне хотелось бы использовать в питоне объкты, которые созданы и работают в С++ коде.
Например, такой main.cpp:

#include <stdlib.h>
#include <iostream>
#include <string>
#include <python.h>

#include "example.hpp"


int main(int argc, char *argv[])
{
setlocale(LC_ALL, "Russian");
A *cppx = new A();

Py_Initialize();
PyRun_SimpleString("import example");

// тут нужно что-то сделать чтобы связать cppx и питон

PyRun_SimpleString("print cppx.getStr()");
Py_Finalize();

system("pause");
return EXIT_SUCCESS;
}
Вот теперь мне нужно передать указатель в питоновский скрипт, чтобы питон работал не с “x = example.A()” как в примере выше, а с уже созданным в C++ коде объектом cppx.
Подскажите как их связать и возможно ли это вообще.
Ведь питон теперь знает что такое класс A… он в модуле example.
Спасибо!



Отредактировано (Окт. 11, 2009 14:47:50)

Офлайн

#5 Окт. 11, 2009 16:00:33

chertov
От:
Зарегистрирован: 2009-07-20
Сообщения: 2
Репутация: +  0  -
Профиль   Отправить e-mail  

Py_Initialize in mixed (embeded and extended) mode

Вот кое-какие продвижения, но с использованием Boost.Python

Вот пример:

#include <stdlib.h>
#include <iostream>

#define BOOST_PYTHON_STATIC_LIB
#include <boost/python.hpp>
using namespace boost::python;

class CppClass {
public:
CppClass()
{
t = 0;
}
int getNum() {
return t;
}
void inc()
{
t++;
}
private:
int t;
};

int main( int argc, char ** argv )
{
setlocale(LC_ALL, "Russian");
try
{
Py_Initialize();

object main_module((handle<>(borrowed(PyImport_AddModule("__main__")))));

object main_namespace = main_module.attr("__dict__");
main_namespace["CppClass"] = class_<CppClass>("CppClass")
.def("getNum",&CppClass::getNum)
.def("inc",&CppClass::inc);

CppClass *cpp = new CppClass();

main_namespace["cpp"] = ptr(cpp);

PyRun_String( "print \"Python: \", cpp.getNum()\n",
Py_file_input, main_namespace.ptr(), main_namespace.ptr());

std::cout << "C++ inc()" << std::endl;
cpp->inc();

PyRun_String( "print \"Python: \", cpp.getNum()\n"
"cpp.inc()\n"
"print \"Python inc()\" \n"
"print \"Python: \", cpp.getNum()\n",
Py_file_input, main_namespace.ptr(), main_namespace.ptr());

std::cout << "C++: " << cpp->getNum() << std::endl;
std::cout << "C++ inc()" << std::endl;
cpp->inc();

PyRun_String( "print \"Python: \", cpp.getNum()\n",
Py_file_input, main_namespace.ptr(), main_namespace.ptr() );

Py_Finalize();
}
catch( error_already_set )
{
PyErr_Print();
}

system("pause");
return EXIT_SUCCESS;
}
На выходе получаем:
Python:  0
C++ inc()
Python: 1
Python inc()
Python: 2
C++: 2
C++ inc()
Python: 3
Для продолжения нажмите любую клавишу . . .
Если кто-нибудь предложит вариант с использованием SWIG о котором я писал выше буду очень благодарен!



Офлайн

#6 Окт. 11, 2009 18:10:37

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

Py_Initialize in mixed (embeded and extended) mode

Технически можно и на SWIG, но я бы настоятельно вам не рекомендовал его использовать. Получающиеся объекты по своим характеристикам очень напоминают “морскую свинку”.
Кроме того, в любом случае было бы правильным сделать модуль. Зарегистрируйте его через PyImport_AppendInittab если не хотите выносить в отдельный pyd/so.

Напоследок: пожалуйста, начинайте новые вопросы в новой теме.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version