Уведомления

Группа в Telegram: @pythonsu

#1 Дек. 6, 2018 15:17:42

djvu
Зарегистрирован: 2018-12-06
Сообщения: 10
Репутация: +  0  -
Профиль   Отправить e-mail  

Динамическая подгрузка и выгрузка модулей.

Есть модуль.

 import TableParser

Есть класс(A) в котором класс (TableParser2) из этого модуля(TableParser) инициализируется и вызывается.
 class A:
   def proc():
        TP = TableParser.TableParser2(self.DEBUG) # self.DEBUG берется из Conf.py
        TP.dictSetConf(self.login, self.password, self.taskName + '_TP', self.IP, self.dbName)

Вопрос в следующем: как при изменении кода в TableParser2 переподключить модуль TableParser так что бы не перезапускать программу. Все изменения подключились на лету при новом вызове proc().

Я делал аналогичную вещь, только из Си вызывал python. Думаю в python так тоже можно сделать.
Спасибо за внимание.

Отредактировано djvu (Дек. 6, 2018 15:28:52)

Офлайн

#2 Дек. 6, 2018 15:22:50

PEHDOM
Зарегистрирован: 2016-11-28
Сообщения: 2196
Репутация: +  294  -
Профиль   Отправить e-mail  

Динамическая подгрузка и выгрузка модулей.

djvu
как при изменении кода в TableParser2 переподключить модуль TableParser так что бы не перезапускать программу.
непонятно какой код вы изменяете в TableParser2. можете привести простенький пример?



==============================
Помещайте код в теги:
[code python][/code]
Бериегите свое и чужое время.

Офлайн

#3 Дек. 6, 2018 15:26:48

djvu
Зарегистрирован: 2018-12-06
Сообщения: 10
Репутация: +  0  -
Профиль   Отправить e-mail  

Динамическая подгрузка и выгрузка модулей.

Была функция:

 class TableParser2:
   def dictSetConf(login, password, taskName, IP, dbName) :
      a = login
      b = password
      c = taskName
      e = IP
      s = dbName
      print("OK")

Изменяем к примеру на :

 class TableParser2:
   def dictSetConf(login, password, taskName, IP, dbName) :
      a = login
      b = password
      c = taskName
      e = IP
      s = dbName
      print("Fail")

при новом вызове функции proc(), метод dictSetConf напечатает Fail, а не OK.

На псевдокоде вижу как-то так:

 class A:
   def proc():
        import TableParser
        TP = TableParser.TableParser2(self.DEBUG) # self.DEBUG берется из Conf.py
        TP.dictSetConf(self.login, self.password, self.taskName + '_TP', self.IP, self.dbName)
        delete TableParser

Отредактировано djvu (Дек. 6, 2018 15:38:27)

Офлайн

#4 Дек. 6, 2018 17:20:23

JOHN_16
От: Россия, Петропавловск-Камчатск
Зарегистрирован: 2010-03-22
Сообщения: 3292
Репутация: +  221  -
Профиль   Отправить e-mail  

Динамическая подгрузка и выгрузка модулей.

а изменяете исходной код во время его выполнения?



_________________________________________________________________________________
полезный блог о python john16blog.blogspot.com

Офлайн

#5 Дек. 6, 2018 21:24:16

PEHDOM
Зарегистрирован: 2016-11-28
Сообщения: 2196
Репутация: +  294  -
Профиль   Отправить e-mail  

Динамическая подгрузка и выгрузка модулей.

djvu
Изменяем к примеру на :
Каким образом вы изменяете “исходний код”? вы создаете класс наследник, или меняете метод класса непосредственно заменяя его другим? по типу :
 import TableParser
def dictSetConf(login, password, taskName, IP, dbName) :
    ......
    print("Fail")
if __name__ == '__main__':
    TableParser.TableParser2.dictSetConf = dictSetConf
у вас в методах класса отсутвует ссылка на инстанс класса, это статические методы или вы просто забыли вписать “self”?



==============================
Помещайте код в теги:
[code python][/code]
Бериегите свое и чужое время.

Отредактировано PEHDOM (Дек. 6, 2018 21:24:42)

Офлайн

#6 Дек. 7, 2018 10:27:54

djvu
Зарегистрирован: 2018-12-06
Сообщения: 10
Репутация: +  0  -
Профиль   Отправить e-mail  

Динамическая подгрузка и выгрузка модулей.

JOHN_16
а изменяете исходной код во время его выполнения?
Да, во время выполнения.

Моя задача такова. Есть сервис в него приходят данные, эти данные мне надо расспарсить.
Вытащить время, дату и прочие данные. К примеру форматы даты могут быть различными и никогда не знаешь какие варианты не учел, например: 07.12.2018, 07.12.18, 07 декабря 2018, 07 декабря 18, 07 дек 2018, 07 дек 18,, и т.п.
Я хочу на лету править исходный код, что бы новые данные обрабатывались без перезапуска сервиса.

Офлайн

#7 Дек. 7, 2018 10:36:47

djvu
Зарегистрирован: 2018-12-06
Сообщения: 10
Репутация: +  0  -
Профиль   Отправить e-mail  

Динамическая подгрузка и выгрузка модулей.

PEHDOM
Каким образом вы изменяете “исходний код”? вы создаете класс наследник, или меняете метод класса непосредственно заменяя его другим? по типу :

Во время выполнения хочу править исходник с классом TableParser.

Офлайн

#8 Дек. 7, 2018 10:48:38

djvu
Зарегистрирован: 2018-12-06
Сообщения: 10
Репутация: +  0  -
Профиль   Отправить e-mail  

Динамическая подгрузка и выгрузка модулей.

Приведу пример как я сделал в своем старом движке на C++ + python.
С++ вызывает интерпритатор python. Здесь исходники python можно править во время выполнения программы. Каждые новые полученные данные будут обрабатываться с внесенными правками в исходный код python без перезапуска.
Мало ли кому пригодится.

Функция вызывается каждый раз как приходят данные. Она упрощена до мест использования python.

 int TrPluginImpl::trprocessing(ODS::IObject& from, ODS::IObject & to)
    {
       
        tparser = new TableParser();
        tparser->init();
        do {
            if (tparser->dict_set_conf((char *) conn_conf->get_login(), (char *) conn_conf->get_password(), (char *) "input_python_psfoi", (char *) conn_conf->get_ip(), (char *) conn_conf->get_name()) == false) {
                ret = -1;
                break;
            }
            QString xml_tmb = (tparser->parse((char *) table.toStdString().c_str(),
                    (char *) table_name.toStdString().c_str(),
                    (char *) from.getStringAttr("uno").toStdString().c_str()).c_str());
                ret = -1;
                break;
            }
        } while (0);
        tparser->clear();
        delete tparser;
        return ret;
    }

Методы по работе с python. TABLEPARSER_PATH путь до исходников python.

 PyObject *TableParser::init() {
    
    do {
        // Инициализировать интерпретатор Python
        Py_Initialize();
        this->sys = PyImport_ImportModule("sys");
        this->sys_path = PyObject_GetAttrString(sys, "path");
        this->folder_path = PyUnicode_FromString((const char*) TABLEPARSER_PATH);
        PyList_Append(this->sys_path, this->folder_path);
        
        //PySys_SetPath((const wchar_t*) VPEPARSER_PATH);
        
        // Построить объект имени
        this->pName = PyUnicode_FromString("TableParser");
        if (!this->pName) {
            PyErr_Print();
            break;
        }
        // Загрузить объект модуля
        this->pModule = PyImport_Import(this->pName);
        if (!pModule) {
            PyErr_Print();
            break;
        }
        // pDict  заимствованная ссылка
        this->pDict = PyModule_GetDict(this->pModule);
        // построить имя вызываемого класса
        this->pClass = PyDict_GetItemString(this->pDict, (const char *) "TableParser");
        // создать экземпляр класса
        if (PyCallable_Check(this->pClass)) {
            this->pInstance = PyObject_CallObject(this->pClass, NULL);
        } else {
            break;
        }
        return this->pInstance;
    } while (0);
    return NULL;
}
void TableParser::clear() {
    // Вернуть ресурсы системе
    Py_XDECREF(this->pInstance);
    Py_XDECREF(this->pClass);
    Py_XDECREF(this->pDict);
    
    Py_XDECREF(this->pModule);
    Py_XDECREF(this->pName);
    Py_XDECREF(this->folder_path);
    Py_XDECREF(this->sys_path);
    Py_XDECREF(this->sys);
    
    // Завершить интерпретатор Python
    Py_Finalize();
}
std::string TableParser::parse(char *table, char *table_type, char *uno, char *uid, int id) {
    /*
    PyObject *pValue = PyObject_CallMethod(this->pInstance, (char *) "parse", (char *) "(ss)", table, table_type);
    if (pValue != NULL) {
        Py_XDECREF(pValue);
    } else {
        PyErr_Print();
    }
    return;
    */
    std::string str;
    
    PyObject *pStr = PyObject_CallMethod(this->pInstance, (char *) "parse", (char *) "(ssssi)", table, table_type, uno, uid, id);
    if (pStr != NULL) {
        //int count = (int) PyByteArray_Size(pStr);
        PyObject* pResultRepr = PyObject_Repr(pStr);
        str = (char *) PyBytes_AS_STRING(PyUnicode_AsEncodedString(pResultRepr, (char *) "utf-8", (char *) "ERROR"));
        
        Py_XDECREF(pResultRepr);
        Py_XDECREF(pStr);
    } else {
        PyErr_Print();
        return std::string("[error]: python call method parse");
        //PyErr_Print();
    }
    //Py_XDECREF(pStr);
    find_and_replace(str, "\\n", "\n");
    find_and_replace(str, "\\t", "\t");
    
    str.erase(str.begin());
    str.erase(str.end() - 1);
    
    return str;
    
}
bool TableParser::dict_set_conf(char *_login, char *_password, char *_id, char *_ip, char *_name) {
    bool ret = false;
    
    PyObject *pVal = PyObject_CallMethod(this->pInstance, (char *) "dict_set_conf", (char *) "(sssss)", _login, _password, _id, _ip, _name);
    
    if (pVal != NULL) {
        ret = (bool) PyBool_Check(pVal);
        
        Py_XDECREF(pVal);
    } else {
        PyErr_Print();
        return ret;
    }
    
    return ret;
}

Отредактировано djvu (Дек. 7, 2018 10:55:29)

Офлайн

#9 Дек. 7, 2018 11:38:34

Rodegast
От: Пятигорск
Зарегистрирован: 2007-12-28
Сообщения: 2679
Репутация: +  182  -
Профиль   Отправить e-mail  

Динамическая подгрузка и выгрузка модулей.

> Есть сервис в него приходят данные, эти данные мне надо расспарсить…Я хочу на лету править исходный код, что бы новые данные обрабатывались без перезапуска сервиса.

exec может выполнить любой текст как код. Его используй, хотя я не вижу никакой проблемы в разных форматах даты.



С дураками и сектантами не спорю, истину не ищу.
Ели кому-то правда не нравится, то заранее извиняюсь.

Офлайн

#10 Дек. 7, 2018 11:55:55

JOHN_16
От: Россия, Петропавловск-Камчатск
Зарегистрирован: 2010-03-22
Сообщения: 3292
Репутация: +  221  -
Профиль   Отправить e-mail  

Динамическая подгрузка и выгрузка модулей.

есть такой модуль importlib - его можно использовать для загрузки питон модуля, после изменения исходного кода того самого модуля.



_________________________________________________________________________________
полезный блог о python john16blog.blogspot.com

Офлайн

Board footer

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

Powered by DjangoBB

Lo-Fi Version