Как перезагрузить 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)
Другие вопросы по тегам