При разработке largeish проекта (разделение в нескольких файлах и папках) в Python с IPython, я сталкиваюсь с проблемой кэшируемых импортированных модулей.
Проблема - это инструкции import module
только читает модуль однажды, даже если тот модуль изменился! Так каждый раз, когда я изменяю что-то в своем пакете, я должен выйти и перезапустить IPython. Болезненный.
Там какой-либо путь состоит в том, чтобы правильно вызвать перезагрузку некоторых модулей? Или, лучше, чтобы так или иначе препятствовать тому, чтобы Python кэшировал их?
Я попробовал несколько подходов, но ни один не работает. В особенности я сталкиваюсь действительно, действительно странные ошибки, как некоторые модули или переменные, загадочно становящиеся равным None
...
Единственный разумный ресурс, который я нашел, Перезагружает модули Python от pyunit, но я не проверил его. Я хотел бы что-то как этот.
Хорошая альтернатива была бы, чтобы IPython перезапустил или перезапустил интерпретатор Python так или иначе.
Так, если Вы разрабатываете в Python, какое решение Вы нашли к этой проблеме?
Править
Ясно дать понять вещи: очевидно, я понимаю, что некоторые старые переменные в зависимости от предыдущего состояния модуля могут слоняться поблизости.Я не против. Тем, почему это настолько трудно в Python вызвать, перезагружают модуль, не имея всего вида странного ошибочного случая?
Строго говоря, если у меня есть свой целый модуль в одном файле module.py
затем следующее хорошо работает:
import sys
try:
del sys.modules['module']
except AttributeError:
pass
import module
obj = module.my_class()
Эта часть кода работает красиво, и я могу разработать, не выходя из IPython в течение многих месяцев.
Однако каждый раз, когда мой модуль сделан из нескольких подмодулей, ад вырывается на свободу:
import os
for mod in ['module.submod1', 'module.submod2']:
try:
del sys.module[mod]
except AttributeError:
pass
# sometimes this works, sometimes not. WHY?
Почему это так отличается для Python, есть ли у меня свой модуль в одном большом файле или в нескольких подмодулях? Почему это приблизилось бы не, работают??
Выход и перезапуск интерпретатора - лучшее решение. Любая стратегия живой перезагрузки или отсутствия кеширования не будет работать без проблем, потому что могут существовать объекты из уже не существующих модулей, и потому, что модули иногда сохраняют состояние, и потому, что даже если ваш вариант использования действительно допускает горячую перезагрузку, это слишком сложно, чтобы думать о нем. стоит того.
import
проверяет, находится ли модуль в sys.modules
, и если это так, он его возвращает. Если вы хотите, чтобы импорт загружал модуль прямо с диска, вы можете сначала удалить соответствующий ключ в sys.modules
.
Существует встроенная функция reload
, которая, учитывая объект модуля, перезагружает его с диска и помещает его в sys.modules
. Edit - фактически он перекомпилирует код из файла на диске, а затем повторно вычислит его в существующем модуле __ dict __
. Что-то потенциально очень отличное от создания нового объекта модуля.
Майк Грэм, однако, прав; получить правильную перезагрузку, если у вас есть хотя бы несколько живых объектов, которые ссылаются на содержимое модуля, который вам больше не нужен. Существующие объекты по-прежнему будут ссылаться на классы, из которых они были созданы, это очевидная проблема, но также все ссылки, созданные с помощью из символа импорта модуля
, по-прежнему будут указывать на любой объект из старой версии модуля. Возможны многие тонко неправильные вещи.
Изменить: Я согласен с консенсусом, что перезапуск интерпретатора на сегодняшний день является самым надежным. Но для целей отладки, я думаю, вы могли бы попробовать что-то вроде следующего. Я уверен, что в некоторых случаях это не сработает, но если вы не делаете ничего слишком сумасшедшего (иначе) с загрузкой модуля в ваш пакет, это может быть полезно.
def reload_package(root_module):
package_name = root_module.__name__
# get a reference to each loaded module
loaded_package_modules = dict([
(key, value) for key, value in sys.modules.items()
if key.startswith(package_name) and isinstance(value, types.ModuleType)])
# delete references to these loaded modules from sys.modules
for key in loaded_package_modules:
del sys.modules[key]
# load each of the modules again;
# make old modules share state with new modules
for key in loaded_package_modules:
print 'loading %s' % key
newmodule = __import__(key)
oldmodule = loaded_package_modules[key]
oldmodule.__dict__.clear()
oldmodule.__dict__.update(newmodule.__dict__)
Что я очень коротко проверил, вот так:
import email, email.mime, email.mime.application
reload_package(email)
печать:
reloading email.iterators
reloading email.mime
reloading email.quoprimime
reloading email.encoders
reloading email.errors
reloading email
reloading email.charset
reloading email.mime.application
reloading email._parseaddr
reloading email.utils
reloading email.mime.base
reloading email.message
reloading email.mime.nonmultipart
reloading email.base64mime