Перезагрузка субмодулей в IPython


363

В настоящее время я работаю над проектом на Python, который содержит подмодули и использует numpy / scipy. Ipython используется в качестве интерактивной консоли. К сожалению, я не очень доволен рабочим процессом, который я использую сейчас, я был бы признателен за некоторые советы.

В IPython фреймворк загружается простой importкомандой. Однако часто бывает необходимо изменить код в одном из подмодулей фреймворка. На данный момент модель уже загружена, и я использую IPython для взаимодействия с ней.

Теперь фреймворк содержит много модулей, которые зависят друг от друга, то есть, когда фреймворк изначально загружен, основной модуль импортирует и конфигурирует субмодули. Изменения в коде выполняются только в том случае, если модуль перезагружается с помощью reload(main_mod.sub_mod). Это громоздко, так как мне нужно перезагрузить все измененные модули индивидуально, используя полный путь. Было бы очень удобно, если reload(main_module)бы также перезагрузить все подмодули, но без перезагрузки numpy / scipy ..


Не могли бы вы подробнее рассказать о том, However, it is often necessary to change code in one of the submodules of the framework.почему necessary to change code? Спасибо
ешь

16
@eat: фреймворк постоянно развивается, поэтому в коде постоянно происходят изменения.
Ален

Ответы:


531

IPython поставляется с некоторой магией автоматической перезагрузки :

%load_ext autoreload
%autoreload 2

Он будет перезагружать все измененные модули каждый раз перед выполнением новой строки. То, как это работает, немного отличается от dreload. Применяются некоторые предостережения, напечатайте, %autoreload?чтобы увидеть, что может пойти не так.


Если вы хотите всегда включать эти настройки, измените файл конфигурации IPython ~/.ipython/profile_default/ipython_config.py[1] и добавьте:

c.InteractiveShellApp.extensions = ['autoreload']     
c.InteractiveShellApp.exec_lines = ['%autoreload 2']

Кредит @Kos через комментарий ниже.

[1] Если у вас нет файла ~/.ipython/profile_default/ipython_config.py, ipython profile createсначала вам нужно позвонить . Или файл может быть расположен в $IPYTHONDIR.


63
У меня c.InteractiveShellApp.extensions = ['autoreload']и c.InteractiveShellApp.exec_lines = ['%autoreload 2']по моему ~/.ipython/profile_default/ipython_config.py.
Кос

4
Это может привести к снижению производительности, поэтому используйте его с осторожностью.
asmeurer

3
Перезагрузка выполняется только при нажатии Enter в оболочке Ipython и обычно не заметна.
pv.

3
Это работает довольно хорошо при отладке пакетов, поэтому для чего нужна dreload, кажется, что dreload слишком инвазивна и выдает ошибку, когда загружаются некоторые пакеты, такие как matplotlib.
Дашесы

3
Если вы используете метод @Kos, убедитесь, что c определен: c = get_config ()
Tickon

27

В IPython 0.12 (и, возможно, ранее) вы можете использовать это:

%load_ext autoreload
%autoreload 2

По сути это то же самое, что и ответ от pv. , за исключением того, что расширение было переименовано и теперь загружается с использованием %load_ext.


20

По какой-то причине ни %autoreload, ни, dreloadпохоже , не работает для ситуации, когда вы импортируете код из одного ноутбука в другой . reloadРаботает только обычный Python :

reload(module)

На основании [1] .


10
В Python 3.4+ вы можете найти перезагрузку в модуле importlib. Смотрите этот вопрос .
Правин

1
Этот метод работает при добавлении метода экземпляра, в отличие от %autoreloadметода. Есть открытый отчет об ошибке, чтобы добавить поддержку %autoreloadдля этого. ,
Иосиф

18

IPython предлагает dreload()рекурсивно перезагрузить все подмодули. Лично я предпочитаю использовать %run()магическую команду (хотя она не выполняет глубокую перезагрузку, как указал Джон Сальватье в комментариях).


11
Я думаю, что (к сожалению)% run script.py перезагружает только тот скрипт, который вы вызываете, а не пакеты, которые он импортирует. Если вы пытаетесь отлаживать создаваемый пакет, это может быть проблемой.
Джон Сальватье

2
NB. dreloadбыл заменен в недавнем IPython (например, IPython 6.0) на deepreload .
Дэн Макинлай

8

Модуль с именем importlibразрешает доступ к внутренним объектам импорта. Особенно, это обеспечивает функцию importlib.reload():

import importlib
importlib.reload(my_module)

В отличие от %autoreload,importlib.reload() также сбросить глобальные переменные, установленные в модуле. В большинстве случаев это то, что вы хотите.

importlibдоступно только с Python 3.1. Для более старой версии вы должны использовать модуль imp.


Единственное решение, которое сработало для меня
gustavz

5

http://shawnleezx.github.io/blog/2015/08/03/some-notes-on-ipython-startup-script/

Чтобы не вводить эти магические функции снова и снова, их можно поместить в сценарий запуска ipython (назовите его суффиксом .py в .ipython / profile_default / startup. Все сценарии python в этой папке будут загружены в соответствии с лексическим порядком), что выглядит следующим образом:

from IPython import get_ipython
ipython = get_ipython()

ipython.magic("pylab")
ipython.magic("load_ext autoreload")
ipython.magic("autoreload 2")

Это также работает, если вы запускаете свой скрипт, например, %run script.pyиз IPython REPL
Патрик Санан

3

Как насчет этого:

import inspect

# needs to be primed with an empty set for loaded
def recursively_reload_all_submodules(module, loaded=None):
    for name in dir(module):
        member = getattr(module, name)
        if inspect.ismodule(member) and member not in loaded:
            recursively_reload_all_submodules(member, loaded)
    loaded.add(module)
    reload(module)

import mymodule
recursively_reload_all_submodules(mymodule, set())

Это должно эффективно перезагрузить все дерево модулей и подмодулей, которые вы ему даете. Вы также можете поместить эту функцию в ваш .ipythonrc (я думаю), чтобы она загружалась каждый раз, когда вы запускаете интерпретатор.


Это выглядит хорошо, однако, возможно, это не касается модулей или членов модулей, которые импортируются с помощью from ... import ...или import ... as. По крайней мере, это часто доставляет мне некоторые проблемы при интерактивной работе на терминале. Я перешел к использованию хранимых макросов в IPython, которые выполняют необходимые операции импорта и настройки, чтобы начать работать в предопределенном состоянии.
Бернхард

Это действительно покрывает from ... import ...и import ... asпока вещь, которую вы импортировали, является модулем. Единственное, на что он не распространяется, это модули в пакете, которые не были загружены из его __init__.pyфайла. Для пакетов вы можете проверить, является ли __path__атрибут модуля каталогом. Если это так, просмотрите его и рекурсивно импортируйте все модули, которые вы могли найти. Я не писал эту часть, потому что автор не просил решения для пакетов.
YH Wong

Действительно, это выглядит хорошо. Я думал об этой возможности, в то же время я ожидал, что будет некоторая встроенная функциональность, т.е. основанная на этом . Однако мне не было понятно, как это использовать. После некоторых копаний, которые должны были произойти, прежде чем я разместил исходный вопрос, я нашел это расширение .
Ален

Также вы можете использовать pkgutilдля получения всех субмодулей в пакете, даже если пакет не импортирует субмодули в верхний модуль. stackoverflow.com/a/1707786/1243926
OSA

Вы также должны сделать: для модуля вsys.modules:
aoeu256

2

Другой вариант:

$ cat << EOF > ~/.ipython/profile_default/startup/50-autoreload.ipy
%load_ext autoreload
%autoreload 2
EOF

Проверено на ipython и ipython3 v5.1.0 на Ubuntu 14.04.


1

Моя стандартная практика для перезагрузки состоит в том, чтобы объединить оба метода после первого открытия IPython:

from IPython.lib.deepreload import reload
%load_ext autoreload
%autoreload 2

Загрузка модулей перед выполнением этого приведет к тому, что они не будут перезагружены, даже с руководством reload(module_name). Я все еще очень редко получаю необъяснимые проблемы с методами класса, не перезагружающими, что я еще не изучал.


1

Обратите внимание, что вышеупомянутое autoreloadработает только в IntelliJ, если вы вручную сохраняете измененный файл (например, используя ctrl + s или cmd + s). Кажется, он не работает с автосохранением.


Я подтверждаю, что это касается и PyCharm.
Цандо

0

На Jupyter Notebooks об Анаконде, сделав это:

%load_ext autoreload
%autoreload 2

произвел сообщение:

Расширение автозагрузки уже загружено. Чтобы перезагрузить его, используйте: %reload_ext autoreload

Похоже, это лучше сделать:

%reload_ext autoreload
%autoreload 2

Информация о версии:

Версия сервера ноутбука - 5.0.0 и работает на: Python 3.6.2 | Anaconda, Inc. | (по умолчанию, 20 сентября 2017 г., 13:35:58) [MSC v.1900 32 бит (Intel)]


0

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.