Ответ 1
Я согласен с консенсусом "не делай этого вообще", но...
Правильный ответ:
import X
reload(X)
from X import Y # or * for that matter
Я видел в этот полезный Q & A, который можно использовать reload(whatever_module)
или, в Python 3, imp.reload(whatever_module)
.
Мой вопрос: что, если бы я сказал from whatever_module import *
для импорта? Тогда у меня нет whatever_module
для ссылки, когда я использую reload()
. Вы, ребята, будете кричать на меня за то, что бросили целый модуль в глобальное пространство имен?:)
Я согласен с консенсусом "не делай этого вообще", но...
Правильный ответ:
import X
reload(X)
from X import Y # or * for that matter
Никогда не используйте import *
; он разрушает читаемость.
Кроме того, имейте в виду, что перезагрузка модулей почти никогда не бывает полезной. Вы не можете предсказать, в каком состоянии ваша программа закончится после перезагрузки модуля, так что это отличный способ получить непонятные, недопустимые ошибки.
А
from module import *
переносит все "экспортированные" объекты из module
и связывает их с именами модулей (или любыми вашими областями-уровнями). Вы можете перезагрузить модуль следующим образом:
reload(sys.modules['module'])
но это не принесет вам никакой пользы: все, что было в вашей области видимости, все еще указывает на старые объекты.
Более чистый ответ - это сочетание хорошего ответа Катскула и использования Охадом Коэном 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 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
, поэтому вам нужно перезагрузить (whatever_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)
для Python 3.7:
from importlib import reload #import function "reload"
import YourModule #import your any modules
reload(YourModule) #reload your module
Функция перезагрузки может быть вызвана из вашей собственной функции
def yourFunc():
reload(YourModule)