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


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

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

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

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

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

The 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() потому что он будет повторно импортировать каждый модуль до того, как его зависимости будут обновлены, что позволит старым ссылкам проникать в новые модули.

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

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

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

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

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 есть и другие параметры магии автоматической загрузки:

%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-реализация import-Python 3.6.4 documentation

те, кто использует 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 будет просто повторно импортировать библиотеку, переданную в качестве аргумента. Это не перезагрузите библиотеки, которые импортирует ваша библиотека. Если вы изменили много файлов и имеете несколько сложный пакет для импорта, вы должны сделать глубокая перезагрузка.

Если у вас 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 переводчика).

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

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

import pythonlib
del pythonlib

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