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

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

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

19 ответов


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

import foo

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

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

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

цитата из документов:

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

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


в Python 3.0–3.3 можно использовать: imp.reload(module)

на BDFL и ответил этот вопрос.

, imp был осужден в 3.4, в пользу importlib (спасибо @Stefan!).

Я думаю, следовательно, теперь вы будете использовать importlib.reload(module), хотя я не уверен.


особенно трудно удалить модуль, если он не является чистым 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 ().


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

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

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

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

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


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

для Python 2 используйте встроенную функцию перезагрузка():

reload(module)

для Python 2 и 3.2–3.3 использовать перезагрузка из модуля imp:

import imp
imp.reload(module)

но imp осуждается начиная с версии 3.4 в пользу importlib, так что использовать:

import importlib
importlib.reload(module)

или

from importlib import reload
reload(module)

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

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

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


принятый ответ не обрабатывает случай from X import 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")

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


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

from importlib import reload

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

например, reload(math) перезагрузит математическую функцию.


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

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

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


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

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

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

%load_ext autoreload
%autoreload 2

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

дальше 2 есть и другие параметры автозапуска magic:

%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.

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

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

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


2018-02-01

  1. модуль foo должен быть успешно импортированы заранее.
  2. from importlib import reload, reload(foo)

31.5. importlib-реализация импорта - Python 3.6.4 документация


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

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


для меня для случая 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'])

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

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

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

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

pip3 install jupyter

у меня было много проблем, пытаясь перезагрузить что-то внутри 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() Он перезагрузит файлы тестов. С Возвышенным Текстом (Python 3.3.6) это происходит много, потому что его интерпретатор никогда не закрывается (если вы не перезапускаете Sublime Text, т. е. Python3.3 переводчика).


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


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

import pythonlib
del pythonlib

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