Найти - Пользователи
Полная версия: Динамическая подгрузка и выгрузка модулей.
Начало » Python для экспертов » Динамическая подгрузка и выгрузка модулей.
1 2
djvu
Есть модуль.
 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 так тоже можно сделать.
Спасибо за внимание.
PEHDOM
djvu
как при изменении кода в TableParser2 переподключить модуль TableParser так что бы не перезапускать программу.
непонятно какой код вы изменяете в TableParser2. можете привести простенький пример?
djvu
Была функция:
 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
JOHN_16
а изменяете исходной код во время его выполнения?
PEHDOM
djvu
Изменяем к примеру на :
Каким образом вы изменяете “исходний код”? вы создаете класс наследник, или меняете метод класса непосредственно заменяя его другим? по типу :
 import TableParser
def dictSetConf(login, password, taskName, IP, dbName) :
    ......
    print("Fail")
if __name__ == '__main__':
    TableParser.TableParser2.dictSetConf = dictSetConf
у вас в методах класса отсутвует ссылка на инстанс класса, это статические методы или вы просто забыли вписать “self”?
djvu
JOHN_16
а изменяете исходной код во время его выполнения?
Да, во время выполнения.

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

Во время выполнения хочу править исходник с классом TableParser.
djvu
Приведу пример как я сделал в своем старом движке на 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;
}
Rodegast
> Есть сервис в него приходят данные, эти данные мне надо расспарсить…Я хочу на лету править исходный код, что бы новые данные обрабатывались без перезапуска сервиса.

exec может выполнить любой текст как код. Его используй, хотя я не вижу никакой проблемы в разных форматах даты.
JOHN_16
есть такой модуль importlib - его можно использовать для загрузки питон модуля, после изменения исходного кода того самого модуля.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB