У меня есть давно работающий сервер Python, и я хотел бы иметь возможность обновлять службу без перезапуска сервера. Как лучше всего это сделать?
if foo.py has changed:
unimport foo <-- How do I do this?
import foo
myfoo = foo.Foo()
вопрос не должен включать `` выгрузку '', поскольку это пока невозможно в python - перезагрузка, однако, является известной парадигмой, как указано ниже
Что делать, если вы хотите «выгрузить», потому что попытка удалить файл .pyc используется кодом?
У меня была такая же проблема при использовании динамического модуля в приложении py2exe. Поскольку py2exe всегда сохраняет байт-код в zip-каталоге, перезагрузка не работает. Но я нашел рабочее решение с использованием модуля import_file. Теперь мое приложение работает нормально.






Вы можете перезагрузить модуль, если он уже был импортирован, используя встроенную функцию reload(Только Python 3.4+):
from importlib import reload
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 modules’ code is recompiled and the module-level code reexecuted, defining a new set of objects which are bound to names in the module’s dictionary. The init function of extension modules is not called a second time. As with all other objects in Python the old objects are only reclaimed after their reference counts drop to zero. The names in the module namespace are updated to point to any new or changed objects. Other references to the old objects (such as names external to the module) are not rebound to refer to the new objects and must be updated in each namespace where they occur if that is desired.
Как вы отметили в своем вопросе, вам придется реконструировать объекты Foo, если класс Foo находится в модуле foo.
на самом деле сервер django dev перезагружается, когда вы меняете файл .. (он перезагружает сервер, а не просто перезагружает модуль)
Ах, вы правы - похоже, они просто перезагружают серверный поток. Ну, просто знайте, что они мог используют перезагрузку, я думаю. :-)
откуда взялась эта функция is_changed? я не вижу по нему документации, и он не работает в моей среде Python 3.1.3 и не работает в 2.6.4.
В командной строке iPython reload, похоже, не следует цепочке зависимостей импорта, он только перезагружает модули, указанные в аргументе.
Python 3 изменил его на import imp / imp.reload (foo)
нет cdleary, Django не может просто использовать перезагрузку: pyunit.sourceforge.net/notes/reloading.html
К вашему сведению, по крайней мере, в Python 2 вы можете просто использовать reload(foo) вместо foo = reload(foo).
Странный. Ответ касается только перезарядки. А как насчет разгрузки?
Как использовать reload для импорта, такого как "from a.b.c import someClass as abcClass" ... reload (abcClass) жалуется, что он не определен.
перезагрузки недостаточно для модулей с зависимостями. См. Ниже: stackoverflow.com/a/438845/456878. Это уже укусило меня и потратило впустую добрые 10 минут.
Это невозможно для расширений C в Windows, потому что файл .pyd уже используется и не может быть обновлен.
Как лучше всего ответить на этот вопрос? Это не работает в моем py27 и / или py34 @jedmao. Вы когда-нибудь узнали, откуда исходит "is_changed"?
@JamesDraper нет, так и не узнал, откуда взялся is_changed ... или забыл. Это было так давно.
К вашему сведению, перезагрузка - источник зла. Например, все экземпляры объектов, созданные с помощью первого импорта, будут ссылаться на старый класс: import foo; bar = foo.Bar(); reload(foo); assert isinstance(bar, foo.Bar) вызовет AssertError
@jedmao @JamesDraper Я почти уверен, что функция is_changed - это просто произвольная функция, которую вам придется написать; это не встроенный. Например, он может открыть файл, соответствующий импортируемому модулю, и сравнить его с кэшированной версией, чтобы увидеть, изменился ли он.
Этот метод может не переопределять ссылки других модулей на перезагруженный модуль. См. stackoverflow.com/a/61617169/2642356 для решения этой проблемы.
Я должен спросить. Что будет после компиляции программы?
reload(module), но только если он полностью автономный. Если что-то еще имеет ссылку на модуль (или любой объект, принадлежащий модулю), вы получите тонкие и любопытные ошибки, вызванные тем, что старый код висит дольше, чем вы ожидали, и такие вещи, как isinstance, не работают в разных версиях тот же код.
Если у вас есть односторонние зависимости, вы также должны перезагрузить все модули, которые зависят от перезагруженного модуля, чтобы избавиться от всех ссылок на старый код. А затем рекурсивно перезагрузите модули, которые зависят от перезагруженных модулей.
Если у вас есть циклические зависимости, что очень часто встречается, например, когда вы имеете дело с перезагрузкой пакета, вы должны выгрузить все модули в группе за один раз. Вы не можете сделать это с reload(), потому что он повторно импортирует каждый модуль до обновления его зависимостей, позволяя старым ссылкам проникать в новые модули.
Единственный способ сделать это в этом случае - взломать sys.modules, который вроде как не поддерживается. Вам нужно будет пройти и удалить каждую запись sys.modules, которую вы хотите перезагрузить при следующем импорте, а также удалить записи, значения которых равны None, чтобы решить проблему реализации, связанную с кешированием неудачного относительного импорта. Это не очень хорошо, но до тех пор, пока у вас есть полностью автономный набор зависимостей, который не оставляет ссылок за пределами своей кодовой базы, он работает.
Вероятно, лучше всего перезапустить сервер. :-)
Разве dreload не подходит специально для этого сценария?
@Josh: нет, это для перезагрузки дерева пакетов, и даже тогда он работает только до тех пор, пока пакет не имеет внешних / циклических зависимостей.
Можете ли вы уточнить часть со значениями None, потому что я столкнулся именно с этой проблемой: я удаляю элементы из sys.modules, и после повторного импорта некоторые импортированные зависимости являются None.
@shclamar: См. stackoverflow.com/questions/1958417/… (и ссылки оттуда) для справки. Мне неясно (даже глядя на код import.c), как записи None смогли вернуться через механизм импорта, когда «настоящие» записи были удалены, и я не могу этого добиться в 2.7; в будущем это, конечно, больше не проблема, поскольку неявный относительный импорт исчез. Между тем, удаление всех записей со значением None, похоже, решает эту проблему.
для новичков было бы лучше, если бы кто-нибудь мог сослаться на то, откуда или из какой библиотеки взялась функция, в случае этого ответа reload (module)
@Eliethesaiyan: вы имеете в виду функцию reload? Он встроен, вам не нужно импортировать какую-либо библиотеку.
@ bobince, думаю, вы подходите для перезагрузки .. Раньше я использовал его из пакета imp
Я написал функцию ниже, которая заменяет содержимое предыдущего модуля новым и, следовательно, решает проблему, справедливо упомянутую @bobince. См. stackoverflow.com/a/61617169/2642356
Особенно сложно удалить модуль, если это не чистый Python.
Вот некоторая информация от: Как мне действительно удалить импортированный модуль?
You can use sys.getrefcount() to find out the actual number of references.
>>> import sys, empty, os
>>> sys.getrefcount(sys)
9
>>> sys.getrefcount(os)
6
>>> sys.getrefcount(empty)
3
Numbers greater than 3 indicate that it will be hard to get rid of the module. The homegrown "empty" (containing nothing) module should be garbage collected after
>>> del sys.modules["empty"]
>>> del empty
as the third reference is an artifact of the getrefcount() function.
Я только что обнаружил, что если модуль является частью пакета, вы должны удалить его и там: setattr(package, "empty", None)
Это правильное решение, особенно если у вас есть пакет с вложенными модулями. reload() перезагружает только самый верхний модуль, и все, что находится внутри него, не будет перезагружено, если вы сначала не удалите его из sys.modules.
В Python 3.0–3.3 вы должны использовать: imp.reload(module)
БДФЛ имеет ответил этот вопрос.
Однако imp устарел в 3.4, в пользу importlib. (спасибо @ Стефан!).
Я считать, поэтому теперь вы бы использовали importlib.reload(module), хотя я не уверен.
Серьезный новичок будет благодарен за то, что узнал о важных нюансах между Python 2 и 3.
@ LoïcFaure-Lacroix: хороший вопрос, понятия не имею. (Думаю, да?) Может быть, стоит задать вопрос.
@ LoïcFaure-Lacroix так же, как reload(__builtins__) действителен в 2.x
@Tarrasch: это модуль Python, который вы хотите перезагрузить, как в примере в вопросе.
@ LoïcFaure-Lacroix да, чертенок может перезагружаться.
@ PaulD.Waite, можете подтвердить, что это работает в Python 3.6.5
Также простое дополнение: если вы хотите перезагрузить изменения в подмодуле, можно выполнить команду "importlib.reload (module.submodule)" ..
Для таких, как я, которые хотят выгрузить все модули (при работе в интерпретаторе Python под Emacs):
for mod in sys.modules.values():
reload(mod)
Более подробная информация находится в Перезагрузка модулей Python.
На самом деле, похоже, что это не работает надежно (в 2.6), потому что не все в sys.modules.values() является модулем. Например: >>> type (sys.modules.values () [1]) <class 'email.LazyImporter'> Итак, если я попытаюсь запустить этот код, он упадет (я знаю, что это не практическое решение, просто указывая на это).
Это даже не работает с более ранними питонами - как написано. Пришлось исключить некоторые имена. Я обновлю сообщение, когда перенесу этот код на свой новый компьютер.
Прекрасно работает в Python 2.7 после некоторых модификаций: if mod and mod.__name__ != "__main__": imp.reload(mod)
У меня это хорошо работает: import imp [reload (m) for m in sys.modules.values () if m, and not ""в м .__ имя and not imp.is_builtin (m .__ name__)]
if 'myModule' in sys.modules:
del sys.modules["myModule"]
+1. Моей целью было провести тесты на питоне. После того, как я загрузил модуль и переименовал некоторые функции, старые имена остались при вызове nose.run(), даже после reload(my_module)%run my_module
Если ваш модуль импортирует свои собственные подмодули, вам может потребоваться удалить и их. Что-то вроде [del(sys.modules[mod] for mod in sys.modules.keys() if mod.startswith('myModule.')].
Не думаю, что разгружает модуль. На Python 3.8: модуль import sys; import json; del sys.modules['json']; print(json.dumps([1])) и json все еще работает, хотя его больше нет в sys.modules.
да, я заметил подчеркнутую запись sys.modules ['_ json'], и она все еще распечатывается после принятия во внимание for mod in [ m for m in sys.modules if m.lstrip('_').startswith('json') ]: del sys.modules[mod]
Ага. Даже при более агрессивном ведении бухгалтерского учета удаление записей вместе со всеми их зависимостями не лишает модуль возможности функционировать. before = [mod for mod in sys.modules] ; import json ; after = [mod for mod in sys.modules if mod not in before] ; for mod in [ m for m in sys.modules if m in after ]: del sys.modules[mod] (кодовый блок не сохранил символы новой строки; обозначает новую строку)
Следующий код обеспечивает совместимость с 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")
В случае перезагрузки мы переназначаем имена верхнего уровня значениям, хранящимся в недавно перезагруженном модуле, который обновляет их.
Заметили проблему, globals () относится к модулю, в котором вы определяете эту функцию, поэтому, если вы определяете его в модуле, отличном от того, который вы вызываете, это не сработает.
Для интерактивного, после >>> from X import Y для перезагрузки делать >>> __import__('X', fromlist='Y')
@ BobStein-VisiBone, есть ли способ заставить это работать, когда fromlist='*'?
Хороший вопрос, не знаю @MikeC. Между прочим, я стремлюсь полностью прекратить использование from в операторах импорта. Просто категоричный import <package> и явный package.symbol в коде. Поймите, что это не всегда возможно или желательно. (Вот одно исключение: из будущего импорта print_function.)
Майк С: мне подходит foo = reload(foo); from foo import *
Добавьте import importlib и importlib.reload( ...
Другой способ - импортировать модуль в функцию. Таким образом, когда функция завершает работу, модуль собирает мусор.
Модуль никогда не будет собирать мусор, потому что глобальная ссылка содержится, по крайней мере, в sys.modules.
Для Python 2 используйте встроенную функцию reload:
reload(module)
Для Python 2а также Python 3,2 — 3.3 используйте reload из модуля imp:
import imp
imp.reload(module)
Для Python ≥3,4, impустарел в пользу importlib, поэтому используйте это:
import importlib
importlib.reload(module)
или же:
from importlib import reload
reload(module)
TL; DR:
Python ≥ 3.4: importlib.reload(module)
Python 3.2 - 3.3: imp.reload(module)
Python 2: reload(module)
для обработки любого из этих случаев: from six import reload_module (сначала, конечно, потребуется pip install six)
@Anentropic: рекомендуется использовать шесть пакетов, но синтаксис - from six.moves import reload_module (док)
В Enthought Traits есть модуль, который неплохо подходит для этого. https://traits.readthedocs.org/en/4.3.0/_modules/traits/util/refresh.html
Он перезагрузит любой модуль, который был изменен, и обновит другие модули и экземпляры объектов, которые его используют. Он не работает большую часть времени с методами __very_private__ и может подавиться наследованием классов, но он экономит мне сумасшедшее количество времени от необходимости перезапускать хост-приложение при написании Guis PyQt или тому подобном, что выполняется внутри программ, таких как Maya или Nuke. . Это не работает, может быть, в 20-30% случаев, но все же невероятно полезно.
Пакет Enthought не перезагружает файлы в тот момент, когда они меняются - вы должны называть это явно - но это не должно быть так сложно реализовать, если вам это действительно нужно.
для меня в случае с 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'])
Этот ответ является прямой копией отсюда: ebanshi.cc/questions/1942/…
У меня было много проблем при попытке перезагрузить что-то внутри 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).
Это современный способ перезагрузки модуля:
from importlib import reload
Если вы хотите поддерживать версии Python старше 3.5, попробуйте следующее:
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.
Или просто from importlib import reload. Тогда вы можете сделать reload(MODULE_NAME). В этой функции нет необходимости.
Я считаю, что modulereload(MODULE_NAME) более понятен, чем просто reload(MODULE_NAME), и имеет меньшую вероятность конфликта с другими функциями.
@RichieBendall Извините, но это совершенно неверный ответ. Функция reload () принимает объект модуля, а не имя модуля ... Прочтите документацию: docs.python.org/3/library/importlib.html#importlib.reload И я согласен с @ pault - это "as modulereload" лишнее.
Я изменил свой ответ, чтобы отразить ваше мнение.
2018-02-01
foo должен быть успешно импортирован заранее.from importlib import reload, reload(foo)31.5. importlib - Реализация импорта - документация Python 3.6.4
Если вы используете нет на сервере, но развивающийся и вам нужно часто перезагружать модуль, вот хороший совет.
Во-первых, убедитесь, что вы используете отличный Оболочка 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.
Конечно, он также будет работать на Jupyter Notebook.
Другой вариант. Обратите внимание, что importlib.reload Python по умолчанию просто повторно импортирует библиотеку, переданную в качестве аргумента. не будет перезагружает библиотеки, которые импортирует ваша библиотека. Если вы изменили много файлов и вам нужно импортировать несколько сложный пакет, вы должны выполнить глубокая перезагрузка.
Если у вас установлен IPython или Юпитер, вы можете использовать функцию для глубокой перезагрузки всех библиотек:
from IPython.lib.deepreload import reload as dreload
dreload(foo)
Если у вас нет Jupyter, установите его с помощью этой команды в своей оболочке:
pip3 install jupyter
И этот Ipython dreload, и reload () из importlib жалуются на reload() argument must be module. Я использую импорт настраиваемой функции и, похоже, не работает. Использование встроенных модулей действительно работает. :-( Это пустая трата времени перезагружать iPython для каждого небольшого изменения, которое я внес в свой код ...
Те, кто использует python 3 и перезагружаются из importlib.
Если у вас есть проблемы, например, кажется, что модуль не перезагружается ... Это связано с тем, что для перекомпиляции pyc требуется некоторое время (до 60 секунд). Я пишу эту подсказку только для того, чтобы вы знали, сталкивались ли вы с подобными проблемами.
Предыдущее решение хорошо только для получения информации о сбросе, но оно не изменит все ссылки (больше, чем reload, но меньше, чем требуется). Чтобы установить все ссылки, мне пришлось зайти в сборщик мусора и переписать там ссылки. Теперь это работает как шарм!
Обратите внимание, что этот не буду работает, если GC выключен, или при перезагрузке данных, которые не контролируются GC. Если вы не хотите связываться с GC, вам может быть достаточно исходного ответа.
Новый код:
import importlib
import inspect
import gc
from weakref import ref
def reset_module(module, inner_modules_also=True):
"""
This function is a stronger form of importlib's `reload` function. What it does, is that aside from reloading a
module, it goes to the old instance of the module, and sets all the (not read-only) attributes, functions and classes
to be the reloaded-module's
:param module: The module to reload (module reference, not the name)
:param inner_modules_also: Whether to treat ths module as a package as well, and reload all the modules within it.
"""
# For the case when the module is actually a package
if inner_modules_also:
submods = {submod for _, submod in inspect.getmembers(module)
if (type(submod).__name__ == 'module') and (submod.__package__.startswith(module.__name__))}
for submod in submods:
reset_module(submod, True)
# First, log all the references before reloading (because some references may be changed by the reload operation).
module_tree = _get_tree_references_to_reset_recursively(module, module.__name__)
new_module = importlib.reload(module)
_reset_item_recursively(module, module_tree, new_module)
def _update_referrers(item, new_item):
refs = gc.get_referrers(item)
weak_ref_item = ref(item)
for coll in refs:
if type(coll) == dict:
enumerator = coll.keys()
elif type(coll) == list:
enumerator = range(len(coll))
else:
continue
for key in enumerator:
if weak_ref_item() is None:
# No refs are left in the GC
return
if coll[key] is weak_ref_item():
coll[key] = new_item
def _get_tree_references_to_reset_recursively(item, module_name, grayed_out_item_ids = None):
if grayed_out_item_ids is None:
grayed_out_item_ids = set()
item_tree = dict()
attr_names = set(dir(item)) - _readonly_attrs
for sub_item_name in attr_names:
sub_item = getattr(item, sub_item_name)
item_tree[sub_item_name] = [sub_item, None]
try:
# Will work for classes and functions defined in that module.
mod_name = sub_item.__module__
except AttributeError:
mod_name = None
# If this item was defined within this module, deep-reset
if (mod_name is None) or (mod_name != module_name) or (id(sub_item) in grayed_out_item_ids) \
or isinstance(sub_item, EnumMeta):
continue
grayed_out_item_ids.add(id(sub_item))
item_tree[sub_item_name][1] = \
_get_tree_references_to_reset_recursively(sub_item, module_name, grayed_out_item_ids)
return item_tree
def _reset_item_recursively(item, item_subtree, new_item):
# Set children first so we don't lose the current references.
if item_subtree is not None:
for sub_item_name, (sub_item, sub_item_tree) in item_subtree.items():
try:
new_sub_item = getattr(new_item, sub_item_name)
except AttributeError:
# The item doesn't exist in the reloaded module. Ignore.
continue
try:
# Set the item
_reset_item_recursively(sub_item, sub_item_tree, new_sub_item)
except Exception as ex:
pass
_update_referrers(item, new_item)
Как написано в ответе @bobince, если уже есть ссылка на этот модуль в другом модуле (особенно если он был импортирован с ключевым словом as, например import numpy as np), этот экземпляр не будет перезаписан.
Это оказалось для меня довольно проблематичным при применении тестов, которые требовали «чистого» состояния модулей конфигурации, поэтому я написал функцию с именем reset_module, которая использует функцию importlibreload и рекурсивно перезаписывает все объявленные атрибуты модуля. Он был протестирован с Python версии 3.6.
import importlib
import inspect
from enum import EnumMeta
_readonly_attrs = {'__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__',
'__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__func__', '__ge__', '__get__',
'__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__',
'__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__',
'__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__', '__weakref__', '__members__', '__mro__', '__itemsize__', '__isabstractmethod__',
'__basicsize__', '__base__'}
def reset_module(module, inner_modules_also=True):
"""
This function is a stronger form of importlib's `reload` function. What it does, is that aside from reloading a
module, it goes to the old instance of the module, and sets all the (not read-only) attributes, functions and classes
to be the reloaded-module's
:param module: The module to reload (module reference, not the name)
:param inner_modules_also: Whether to treat ths module as a package as well, and reload all the modules within it.
"""
new_module = importlib.reload(module)
reset_items = set()
# For the case when the module is actually a package
if inner_modules_also:
submods = {submod for _, submod in inspect.getmembers(module)
if (type(submod).__name__ == 'module') and (submod.__package__.startswith(module.__name__))}
for submod in submods:
reset_module(submod, True)
_reset_item_recursively(module, new_module, module.__name__, reset_items)
def _reset_item_recursively(item, new_item, module_name, reset_items=None):
if reset_items is None:
reset_items = set()
attr_names = set(dir(item)) - _readonly_attrs
for sitem_name in attr_names:
sitem = getattr(item, sitem_name)
new_sitem = getattr(new_item, sitem_name)
try:
# Set the item
setattr(item, sitem_name, new_sitem)
try:
# Will work for classes and functions defined in that module.
mod_name = sitem.__module__
except AttributeError:
mod_name = None
# If this item was defined within this module, deep-reset
if (mod_name is None) or (mod_name != module_name) or (id(sitem) in reset_items) \
or isinstance(sitem, EnumMeta): # Deal with enums
continue
reset_items.add(id(sitem))
_reset_item_recursively(sitem, new_sitem, module_name, reset_items)
except Exception as ex:
raise Exception(sitem_name) from ex
Примечание: Используйте осторожно! Их использование в непериферийных модулях (например, в модулях, определяющих классы, используемые извне) может привести к внутренним проблемам в Python (например, проблемам травления / расправления).
Если вы столкнулись со следующей ошибкой, этот ответ может помочь вам найти решение:
Traceback (most recent call last): File "FFFF", line 1, in NameError: name 'YYYY' is not defined
ИЛИ ЖЕ
Traceback (most recent call last):
File "FFFF", line 1, in
File "/usr/local/lib/python3.7/importlib/__init__.py", line 140, in reload
raise TypeError("reload() argument must be a module")
TypeError: reload() argument must be a moduleЕсли у вас есть импорт, подобный приведенному ниже, вам может потребоваться использовать sys.modules для получения модуля, который вы хотите перезагрузить:
import importlib
import sys
from YYYY.XXX.ZZZ import CCCC
import AAA.BBB.CC
def reload(full_name)
if full_name in sys.modules:
importlib.reload(sys.modules[full_name])
reload('YYYY.XXX.ZZZ') # this is fine in both cases
reload('AAA.BBB.CC')
importlib.reload(YYYY.XXX.ZZZ) # in my case: this fails
importlib.reload(AAA.BBB.CC) # and this is ok
Основная проблема в том, что importlib.reload принимает только модуль, а не строку.
Удаление модулей из sys.modules требует также удаления типов 'Никто'.
Способ 1:
import sys
import json ## your module
for mod in [ m for m in sys.modules if m.lstrip('_').startswith('json') or sys.modules[m] == None ]: del sys.modules[mod]
print( json.dumps( [1] ) ) ## test if functionality has been removed
Метод 2 с использованием бухгалтерских записей для удаления зависимостей все:
import sys
before_import = [mod for mod in sys.modules]
import json ## your module
after_import = [mod for mod in sys.modules if mod not in before_import]
for mod in [m for m in sys.modules if m in after_import or sys.modules[m] == None]: del sys.modules[mod]
print( json.dumps( [2] ) ) ## test if functionality has been removed
Необязательно, чтобы убедиться, что все записи отсутствуют, если вы так выберете:
import gc
gc.collect()
Подсказка: «импорт» не означает «загрузка», это означает «загрузить, если еще не загружен, а затем импортировать в пространство имен».