Как выгрузить (перезагрузить) модуль?

У меня есть длительный Python-сервер и вы хотите обновить сервис без перезагрузки сервера. Какой лучший способ сделать это?

if foo.py has changed:
    unimport foo  <-- How do I do this?
    import foo
    myfoo = foo.Foo()

Ответ 1

Вы можете перезагрузить модуль, когда он уже был импортирован, используя встроенную функцию reload:

from importlib import reload  # Python 3.4+ only.
import foo

while True:
    # Do some things.
    if is_changed(foo):
        foo = reload(foo)

В Python 3 reload была перенесена в модуль imp. В 3.4, imp был устаревшим в пользу importlib, и к последнему добавилась reload. При таргетинге 3 или более поздней версии либо ссылайтесь на соответствующий модуль, когда вы вызываете reload или импортируете его.

Я думаю, что это то, что вы хотите. Веб-серверы, такие как сервер разработки Django, используют это, чтобы вы могли видеть эффекты изменений кода без перезапуска самого процесса сервера.

Цитировать из документов:

Код модулей Python перекомпилируется, а код модуля-уровня переустанавливается, определяя новый набор объектов, привязанных к именам в словаре модулей. Функция init модулей расширения не вызывается второй раз. Как и все другие объекты в Python, старые объекты восстанавливаются только после того, как их отсчеты ссылок упадут до нуля. Имена в пространстве имен модулей обновляются, чтобы указывать на любые новые или измененные объекты. Другие ссылки на старые объекты (например, имена, внешние по отношению к модулю) не восстанавливаются, чтобы ссылаться на новые объекты и должны обновляться в каждом пространстве имен, где они встречаются, если это необходимо.

Как вы отметили в своем вопросе, вам придется восстанавливать объекты Foo если класс Foo находится в модуле foo.

Ответ 3

Это может быть особенно сложно удалить модуль, если он не является чистым Python.

Вот некоторая информация из: Как я могу удалить импортированный модуль?

Вы можете использовать sys.getrefcount(), чтобы узнать фактическое количество ссылки.

>>> import sys, empty, os
>>> sys.getrefcount(sys)
9
>>> sys.getrefcount(os)
6
>>> sys.getrefcount(empty)
3

Числа, превышающие 3, показывают, что будет трудно избавиться от модуль. Домашний "пустой" (не содержащий ничего) модуль должен быть мусор, собранный после

>>> del sys.modules["empty"]
>>> del empty

поскольку третья ссылка является артефактом функции getrefcount().

Ответ 4

reload(module), но только если он полностью автономный. Если что-либо еще имеет ссылку на модуль (или любой объект, принадлежащий модулю), то вы получите тонкие и любопытные ошибки, вызванные тем, что старый код висит дольше, чем вы ожидали, и такие вещи, как isinstance, не работают с разными версии одного и того же кода.

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

Если у вас есть циклические зависимости, что очень часто встречается, например, когда вы имеете дело с перезагрузкой пакета, вы должны разгрузить все модули в группе за один раз. Вы не можете сделать это с помощью reload(), потому что он будет повторно импортировать каждый модуль до того, как его зависимости будут обновлены, что позволит использовать старые ссылки для ползучести в новые модули.

Единственный способ сделать это в этом случае - взломать sys.modules, что является неподдерживаемым. Вам нужно будет пройти и удалить каждую запись sys.modules, которую вы хотели бы перезагрузить при следующем импорте, а также удалить записи, значения которых None для решения проблемы с реализацией, связанной с кэшированием, при неудачном относительном импорте. Это не очень приятно, но до тех пор, пока у вас есть полностью автономный набор зависимостей, который не оставляет ссылок за пределами его кодовой базы, он работоспособен.

Вероятно, лучше всего перезапустить сервер.: -)

Ответ 5

if 'myModule' in sys.modules:  
    del sys.modules["myModule"]

Ответ 7

Следующий код позволяет вам совместимость с Python 2/3:

try:
    reload
except NameError:
    # Python 3
    from imp import reload

Вы можете использовать его как reload() в обеих версиях, что упрощает процесс.

Ответ 8

Принятый ответ не обрабатывает случай X импорта Y. Этот код обрабатывает его и стандартный случай импорта:

def importOrReload(module_name, *names):
    import sys

    if module_name in sys.modules:
        reload(sys.modules[module_name])
    else:
        __import__(module_name, fromlist=names)

    for name in names:
        globals()[name] = getattr(sys.modules[module_name], name)

# use instead of: from dfly_parser import parseMessages
importOrReload("dfly_parser", "parseMessages")

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

Ответ 9

Это современный способ перезагрузки модуля:

from importlib import reload

Если вы хотите поддерживать версии Python старше 3.4, попробуйте это:

from sys import version_info
if version_info[0] < 3:
    pass # Python 2 has built in reload
elif version_info[0] == 3 and version_info[1] <= 4:
    from imp import reload # Python 3.0 - 3.4 
else:
    from importlib import reload # Python 3.5+

Чтобы использовать его, запустите reload(MODULE), заменив MODULE на модуль, который вы хотите перезагрузить.

Например, reload(math) перезагрузит math модуль.

Ответ 10

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

Во-первых, убедитесь, что вы используете превосходную оболочку IPython из проекта Jupyter Notebook. После установки Jupyter вы можете запустить его с ipython, или jupyter console, или, что еще лучше, с jupyter qtconsole, которая даст вам красивую раскрашенную консоль с дополнением кода в любой ОС.

Теперь в вашей оболочке введите:

%load_ext autoreload
%autoreload 2

Теперь каждый раз, когда вы запускаете ваш скрипт, ваши модули будут перезагружаться.

Помимо 2, есть и другие варианты магии автозагрузки:

%autoreload
Reload all modules (except those excluded by %aimport) automatically now.

%autoreload 0
Disable automatic reloading.

%autoreload 1
Reload all modules imported with %aimport every time before executing the Python code typed.

%autoreload 2
Reload all modules (except those excluded by %aimport) every time before
executing the Python code typed.

Ответ 11

Для таких, как я, которые хотят выгрузить все модули (при запуске в интерпретаторе Python под Emacs):

   for mod in sys.modules.values():
      reload(mod)

Дополнительная информация находится в Перезагрузка модулей Python.

Ответ 12

Enthought Traits имеет модуль, который работает достаточно хорошо для этого. https://traits.readthedocs.org/en/4.3.0/_modules/traits/util/refresh.html

Он перезагрузит любой измененный модуль и обновит другие модули и объекты, которые его используют. Он не работает большую часть времени с __very_private__ методов __very_private__ и может __very_private__ наследование классов, но это избавляет меня от сумасшедшего времени от необходимости перезапуска приложения-хозяина при написании PyQt guis или материала, который запускается внутри таких программ, как Maya или Nuke, Это не работает, возможно, в 20-30% случаев, но это все еще невероятно полезно.

Пакет Enthought не перезагружает файлы в тот момент, когда они меняются - вы должны называть это явно - но это не должно быть так сложно реализовать, если вам это действительно нужно

Ответ 13

Те, кто использует python 3 и перезагружают из importlib.

Если у вас есть проблемы, подобные тому, что кажется, что модуль не перезагружается... Это потому, что для перекомпиляции pyc (до 60 секунд) требуется некоторое время. Я пишу этот намек только для того, чтобы вы знали, что вы столкнулись с такой проблемой.

Ответ 15

Другой вариант. Посмотрите, что Python default importlib.reload просто importlib.reload библиотеку, переданную в качестве аргумента. Он не перезагрузит библиотеки, которые импортируют ваш lib. Если вы изменили много файлов и имеете несколько сложный пакет для импорта, вы должны сделать глубокую перезагрузку.

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

from IPython.lib.deepreload import reload as dreload
dreload(foo)

Если у вас нет Jupyter, установите его с помощью этой команды в своей оболочке:

pip3 install jupyter

Ответ 16

для меня в случае с Abaqus это так, как это работает. Представьте, что ваш файл Class_VerticesEdges.py

sys.path.append('D:\...\My Pythons')
if 'Class_VerticesEdges' in sys.modules:  
    del sys.modules['Class_VerticesEdges']
    print 'old module Class_VerticesEdges deleted'
from Class_VerticesEdges import *
reload(sys.modules['Class_VerticesEdges'])

Ответ 17

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

Ответ 18

У меня много проблем с попыткой перезагрузить что-то внутри Sublime Text, но, наконец, я смог написать эту утилиту для перезагрузки модулей в Sublime Text на основе кода sublime_plugin.py для перезагрузки модулей.

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

def reload_module(full_module_name):
    """
        Assuming the folder `full_module_name` is a folder inside some
        folder on the python sys.path, for example, sys.path as `C:/`, and
        you are inside the folder `C:/Path With Spaces` on the file 
        `C:/Path With Spaces/main.py` and want to re-import some files on
        the folder `C:/Path With Spaces/tests`

        @param full_module_name   the relative full path to the module file
                                  you want to reload from a folder on the
                                  python `sys.path`
    """
    import imp
    import sys
    import importlib

    if full_module_name in sys.modules:
        module_object = sys.modules[full_module_name]
        module_object = imp.reload( module_object )

    else:
        importlib.import_module( full_module_name )

def run_tests():
    print( "\n\n" )
    reload_module( "Path With Spaces.tests.semantic_linefeed_unit_tests" )
    reload_module( "Path With Spaces.tests.semantic_linefeed_manual_tests" )

    from .tests import semantic_linefeed_unit_tests
    from .tests import semantic_linefeed_manual_tests

    semantic_linefeed_unit_tests.run_unit_tests()
    semantic_linefeed_manual_tests.run_manual_tests()

if __name__ == "__main__":
    run_tests()

Если вы запускаете в первый раз, это должно загрузить модуль, но если позже вы снова сможете использовать метод/функцию run_tests(), он перезагрузит файлы тестов. С Sublime Text (Python 3.3.6) это происходит очень часто, потому что его интерпретатор никогда не закрывается (если вы не перезапустите Sublime Text, т.е. Интерпретатор Python3.3).

Ответ 19

Операцию unload можно легко выполнить следующим образом:

import pythonlib
del pythonlib

у вас больше ничего не будет связано с этой библиотекой.