Как выгрузить (перезагрузить) модуль Python? - PullRequest
717 голосов
/ 13 января 2009

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

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

Ответы [ 18 ]

671 голосов
/ 13 января 2009

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

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

243 голосов
/ 10 октября 2009

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

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

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

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

84 голосов
/ 28 января 2009

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

62 голосов
/ 13 января 2009

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

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

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

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

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

61 голосов
/ 07 июля 2010
if 'myModule' in sys.modules:  
    del sys.modules["myModule"]
52 голосов
/ 09 августа 2015

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

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)
21 голосов
/ 20 ноября 2012

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

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

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

16 голосов
/ 28 сентября 2014

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

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

14 голосов
/ 21 ноября 2017

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

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 голосов
/ 18 марта 2018

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

Сначала убедитесь, что вы используете превосходную оболочку 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.
...