Как перезагрузить Python-модуль, импортированный с помощью `from module import *`
Я видел в этом полезном Q&A, что можно использовать reload(whatever_module)
или, в Python 3, imp.reload(whatever_module)
,
Мой вопрос в том, что если бы я сказал from whatever_module import *
импортировать? Тогда у меня нет whatever_module
ссылаться на когда я использую reload()
, Вы, ребята, будете кричать на меня за то, что я выбросил целый модуль в глобальное пространство имен?:)
6 ответов
Я согласен с консенсусом "не делай этого вообще", но...
Правильный ответ:
import X
reload(X)
from X import Y # or * for that matter
Никогда не используйте import *
; это разрушает читабельность.
Также помните, что перезагрузка модулей практически никогда не бывает полезной. Вы не можете предсказать, в каком состоянии окажется ваша программа после перезагрузки модуля, поэтому это отличный способ получить непонятные, невоспроизводимые ошибки.
Более чистый ответ - это сочетание хорошего ответа Катскула и использования Охадом Коэном sys.module
и прямое переопределение:
import sys
Y = reload(sys.module["X"]).Y # reload() returns the new module
На самом деле, делая import X
создает новый символ (X
), который может быть переопределен в следующем коде, что не является необходимым (тогда как sys
это общий модуль, так что этого не должно происходить).
Интересным моментом здесь является то, что from X import Y
не добавляет X
в пространство имен, но добавляет модуль X
к списку известных модулей (sys.modules
), что позволяет перезагрузить модуль (и получить доступ к его новому содержимому).
В более общем случае, если необходимо обновить несколько импортированных символов, удобнее импортировать их следующим образом:
import sys
reload(sys.module["X"]) # No X symbol created!
from X import Y, Z, T
from module import *
принимает все "экспортированные" объекты из module
и связывает их с именами на уровне модулей (или какими-либо вашими областями действия). Вы можете перезагрузить модуль как:
reload(sys.modules['module'])
но это не принесет вам никакой пользы: имена независимо от того, в какой области вы находитесь, все еще указывают на старые объекты.
Я нашел другой способ справиться с перезагрузкой модуля при импорте, например:
from directory.module import my_func
Приятно знать, как вообще импортируются модули. Модуль ищется вsys.modules
толковый словарь. Если он уже существует в sys.modules - модуль больше не будет импортирован.
Поэтому, если мы хотим перезагрузить наш модуль, мы можем просто удалить его из sys.modules и снова импортировать:
import sys
from directory.module import my_func
my_func('spam')
# output: 'spam'
# here I have edited my_func in module.py
my_func('spam') # same result as above
#output: 'spam'
del sys.modules[my_func.__module__]
from directory.module import my_func
my_func('spam') # new result
#output: 'spam spam spam spam spam'
Если вы хотите получить перезагруженный модуль при запуске всего скрипта, вы можете использовать обработчик исключений:
try:
del sys.modules[my_func.__module__]
except NameError as e:
print("""Can't remove module that haven't been imported.
Error: {}""".format(e))
from utils.module import my_func
..........
# code of the script here
При импорте используя from whatever_module import whatever
, whatever
считается частью импортирующего модуля, поэтому для его перезагрузки вам следует перезагрузить ваш модуль. Но просто перезагрузив свой модуль, вы все равно получите старый whatever
- из уже импортированных whatever_module
, так что вам нужно перезагрузить (what_module), а затем перезагрузить ваш модуль:
# reload(whatever_module), if you imported it
reload(sys.modules['whatever_module'])
reload(sys.modules[__name__])
если вы использовали from whatever_module import whatever
Вы также можете рассмотреть
whatever=reload(sys.modules['whatever_module']).whatever
или же
whatever=reload(whatever_module).whatever
import re
for mod in sys.modules.values():
if re.search('name', str(mod)):
reload(mod)
Для питона 3.7:
from importlib import reload #import function "reload"
import YourModule #import your any modules
reload(YourModule) #reload your module
Функция перезагрузки может быть вызвана из вашей собственной функции
def yourFunc():
reload(YourModule)