Динамическая загрузка модулей Python

В Python, как Вы динамично добавляете модули к пакету, в то время как Ваша программа работает.

Я хочу смочь добавить модули к каталогу пакета от внешнего процесса и смочь использовать те новые модули в моей программе:

import package

def doSomething(name):
    pkg = __import__("package." + name)
    mod = getattr(pkg, name)
    mod.doSomething()

Как я делаю это?

50
задан 4 revs, 4 users 65%No Name 25 July 2019 в 22:07
поделиться

5 ответов

Ваш код почти правильный.

См. __ import __ function.

def doSomething(name):
    name = "package." + name
    mod = __import__(name, fromlist=[''])
    mod.doSomething()
55
ответ дан 7 November 2019 в 10:49
поделиться

Один трюк с ответом Бастьена ... Функция __ import __ () возвращает объект пакета, а не объект модуля. Если вы используете следующую функцию, она динамически загрузит модуль из пакета и вернет вам модуль, а не пакет.

def my_import(name):
    mod = __import__(name)
    components = name.split('.')
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod

Затем вы можете сделать:

mod = my_import('package.' + name)
mod.doSomething()
9
ответ дан 7 November 2019 в 10:49
поделиться

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

def loadModules():
    res = {}
    import os
    # check subfolders
    lst = os.listdir("services")
    dir = []
    for d in lst:
        s = os.path.abspath("services") + os.sep + d
        if os.path.isdir(s) and os.path.exists(s + os.sep + "__init__.py"):
            dir.append(d)
    # load the modules
    for d in dir:
        res[d] = __import__("services." + d, fromlist = ["*"])
    return res

Эта другая функция предназначена для создания экземпляра объекта с помощью класс, определенный в одном из модулей, загруженных первой функцией:

def getClassByName(module, className):
    if not module:
        if className.startswith("services."):
            className = className.split("services.")[1]
        l = className.split(".")
        m = __services__[l[0]]
        return getClassByName(m, ".".join(l[1:]))
    elif "." in className:
        l = className.split(".")
        m = getattr(module, l[0])
        return getClassByName(m, ".".join(l[1:]))
    else:
        return getattr(module, className)

Простой способ использования этих функций:

mods = loadModules()
cls = getClassByName(mods["MyModule"], "submodule.filepy.Class")
obj = cls()

Очевидно, вы можете заменить все ссылки на подпапку "services" параметрами.

23
ответ дан 7 November 2019 в 10:49
поделиться

Добавьте каталог модуля в sys.path и используйте обычный оператор import .

-1
ответ дан 7 November 2019 в 10:49
поделиться

Для обнаружения изменений в каталоге в Linux вы можете использовать pyinotify ( здесь - хороший рабочий пример); на Mac - fsevents (через пакет PyObjC, поставляемый с вашим Mac); в Windows: Уведомления об изменении каталога через win32api (или модуль стандартной библиотеки Python ctypes ). AFAIK, никто не объединил эти различные подходы в один портативный пакет. (Конечно, в худшем случае вы можете вернуться к «более низким технологиям», таким как периодические опросы, как статья Тима Голдена , возможно, с легким «предупреждением от внешнего процесса» через сигнал и т. Д. ).

Как только вы получите уведомление и имя нового или измененного модуля,

3
ответ дан 7 November 2019 в 10:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: