Препятствуйте тому, чтобы Python кэшировал импортированные модули

При разработке 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, есть ли у меня свой модуль в одном большом файле или в нескольких подмодулях? Почему это приблизилось бы не, работают??

48
задан Olivier Verdier 27 May 2010 в 13:17
поделиться

2 ответа

Выход и перезапуск интерпретатора - лучшее решение. Любая стратегия живой перезагрузки или отсутствия кеширования не будет работать без проблем, потому что могут существовать объекты из уже не существующих модулей, и потому, что модули иногда сохраняют состояние, и потому, что даже если ваш вариант использования действительно допускает горячую перезагрузку, это слишком сложно, чтобы думать о нем. стоит того.

12
ответ дан 26 November 2019 в 19:02
поделиться

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
24
ответ дан 26 November 2019 в 19:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: