Ponowne ładowanie submodułów w IPython

363

Obecnie pracuję nad projektem Pythona, który zawiera podmoduły i używa numpy / scipy. Ipython jest używany jako interaktywna konsola. Niestety nie jestem zadowolony z przepływu pracy, którego używam teraz, byłbym wdzięczny za porady.

W IPython środowisko jest ładowane za pomocą prostej importkomendy. Jednak często konieczna jest zmiana kodu w jednym z submodułów frameworka. W tym momencie model jest już załadowany i używam IPython do interakcji z nim.

Teraz struktura zawiera wiele modułów, które są od siebie zależne, tzn. Gdy platforma jest początkowo ładowana, moduł główny importuje i konfiguruje submoduły. Zmiany w kodzie są wykonywane tylko wtedy, gdy moduł zostanie przeładowany przy użyciu reload(main_mod.sub_mod). Jest to uciążliwe, ponieważ muszę ponownie ładować wszystkie zmienione moduły indywidualnie, korzystając z pełnej ścieżki. Byłoby bardzo wygodne, gdyby reload(main_module)przeładował również wszystkie podmoduły, ale bez przeładowywania numpy / scipy ..

Alain
źródło
Czy chciałbyś rozwinąć więcej tematów However, it is often necessary to change code in one of the submodules of the framework.Więc dlaczego necessary to change code? Dzięki
zjedz
16
@eat: Framework jest ciągle rozwijany, więc ciągle zmieniają się podstawy kodu.
Alain

Odpowiedzi:

531

IPython zawiera pewną magię automatycznego przeładowywania :

%load_ext autoreload
%autoreload 2

Przeładuje wszystkie zmienione moduły za każdym razem przed wykonaniem nowej linii. Sposób działania jest nieco inny niż dreload. Obowiązują pewne zastrzeżenia, wpisz, %autoreload?aby zobaczyć, co może pójść nie tak.


Jeśli chcesz zawsze włączać te ustawienia, zmodyfikuj plik konfiguracyjny IPython ~/.ipython/profile_default/ipython_config.py[1] i dołącz:

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

Kredyt @Kos poprzez komentarz poniżej.

[1] Jeśli nie masz pliku ~/.ipython/profile_default/ipython_config.py, musisz ipython profile createnajpierw zadzwonić . Lub plik może znajdować się w $IPYTHONDIR.

pv.
źródło
63
Mam c.InteractiveShellApp.extensions = ['autoreload']i c.InteractiveShellApp.exec_lines = ['%autoreload 2']w sobie ~/.ipython/profile_default/ipython_config.py.
Kos
4
Może to być hit wydajności, więc używaj go ostrożnie.
asmeurer,
3
Przeładowanie jest wykonywane tylko po naciśnięciu klawisza Enter w powłoce Ipython i zwykle nie jest zauważalne.
pv.
3
Działa to całkiem dobrze podczas debugowania pakietów, więc jaki jest cel dreload, wydaje się, że dreload jest zbyt inwazyjny i wyświetla błąd, gdy niektóre pakiety, takie jak matplotlib, są załadowane.
dashy
3
Jeśli używasz metody @Kos, upewnij się, że c jest zdefiniowane: c = get_config ()
Tickon
27

W IPython 0.12 (i prawdopodobnie wcześniej) możesz użyć tego:

%load_ext autoreload
%autoreload 2

Jest to w zasadzie to samo co odpowiedź pv. , z wyjątkiem tego, że rozszerzenie zostało zmienione i jest teraz ładowane przy użyciu %load_ext.

RafG
źródło
20

Z jakiegoś powodu ani %autoreloadnie dreloadwydaje się, aby działał w sytuacji, gdy importujesz kod z jednego notatnika do drugiego . reloadDziała tylko zwykły Python :

reload(module)

Na podstawie [1] .

Dennis Golomazov
źródło
10
W Python 3.4+ można znaleźć przeładowanie w module importlib. Zobacz to pytanie .
Praveen
1
Ta metoda działa w przypadku dodawania metody instancji, w przeciwieństwie do %autoreloadtechniki. Istnieje otwarty raport o błędach, do którego można dodać wsparcie %autoreload. .
ijoseph
18

IPython oferuje dreload()rekurencyjne przeładowanie wszystkich podmodułów. Osobiście wolę używać %run()magicznego polecenia (chociaż nie wykonuje ono głębokiego przeładowania, jak zauważył John Salvatier w komentarzach).

Sven Marnach
źródło
11
Myślę, że (niestety)% run script.py przeładowuje tylko skrypt, który wywołujesz, a nie pakiety, które importuje. Jeśli próbujesz debugować budowany pakiet, może to być uciążliwe.
John Salvatier
2
NB dreloadzostał zastąpiony w ostatnim IPython (np. IPython 6.0) przez deepreload .
Dan Mackinlay
8

Nazwany moduł importlibpozwala na dostęp do importowanych elementów wewnętrznych. W szczególności zapewnia funkcję importlib.reload():

import importlib
importlib.reload(my_module)

Przeciwnie %autoreload, importlib.reload()zresetuj także zmienne globalne ustawione w module. W większości przypadków jest to, czego chcesz.

importlibjest dostępna tylko od wersji Python 3.1. W przypadku starszej wersji musisz użyć modułu imp.

Jérôme Pouiller
źródło
jedyne rozwiązanie, które dla mnie
zadziałało
5

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

Aby uniknąć wielokrotnego wpisywania tych magicznych funkcji, można je umieścić w skrypcie startowym ipython (nazwij je sufiksem .py w .ipython / default_default / startup. Wszystkie skrypty python w tym folderze zostaną załadowane zgodnie z kolejnością leksykalną), które wygląda następująco:

from IPython import get_ipython
ipython = get_ipython()

ipython.magic("pylab")
ipython.magic("load_ext autoreload")
ipython.magic("autoreload 2")
Pegaz
źródło
Wydaje się to również działać, jeśli uruchamiasz skrypt np. %run script.pyZ IPython REPL
Patrick Sanan
3

Co powiesz na to:

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())

To powinno skutecznie przeładować całe drzewo modułów i podmodułów, które mu dasz. Możesz także umieścić tę funkcję w swoim .ipythonrc (myślę), aby była ładowana przy każdym uruchomieniu interpretera.

YH Wong
źródło
Wygląda to dobrze, jednak możliwe, że nie obejmuje modułów ani elementów modułów importowanych za pomocą from ... import ...lub import ... as. Przynajmniej sprawia mi to często problemy podczas interaktywnej pracy na terminalu. Przeszedłem do używania przechowywanych makr w IPython, które wykonują niezbędne importy i konfiguracje, aby rozpocząć pracę w predefiniowanym stanie.
Bernhard
W rzeczywistości obejmuje to from ... import ...i import ... astak długo, jak importujesz moduł. Jedyne, czego nie obejmuje, to moduły w pakiecie, które nie zostały załadowane z jego __init__.pypliku. W przypadku pakietów prawdopodobnie można sprawdzić, czy __path__atrybutem modułu jest katalog. Jeśli tak, przejdź do niego i zaimportuj rekurencyjnie wszystkie moduły, które możesz znaleźć. Nie napisałem tej części, ponieważ autor nie poprosił o rozwiązanie dla pakietów.
YH Wong
Rzeczywiście wygląda to dobrze. Myślałem o tej możliwości, jednocześnie spodziewałbym się, że będzie trochę wbudowanej funkcjonalności, czyli na tej podstawie . Jednak nie było dla mnie jasne, jak tego użyć. Po kilku kopaniach, które powinny były nastąpić, zanim opublikowałem oryginalne pytanie, znalazłem to rozszerzenie .
Alain
Możesz także użyć, pkgutilaby uzyskać wszystkie submoduły w pakiecie, nawet jeśli pakiet nie importuje submodułów do górnego modułu. stackoverflow.com/a/1707786/1243926
osa
musisz także zrobić: dla modułu insys.modules:
aoeu256
2

Inna opcja:

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

Zweryfikowano na ipython i ipython3 v5.1.0 na Ubuntu 14.04.

Czad
źródło
1

Moją standardową praktyką dotyczącą przeładowywania jest połączenie obu metod po pierwszym otwarciu IPython:

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

Ładowanie modułów przed zrobieniem tego spowoduje, że nie zostaną ponownie załadowane, nawet z instrukcją reload(module_name). Nadal bardzo rzadko spotykam się z niewytłumaczalnymi problemami z metodami klasowymi, które nie przeładowują się, a których jeszcze nie zbadałem.

ryanjdillon
źródło
1

Zauważ, że wyżej wymienione autoreloaddziała tylko w IntelliJ, jeśli ręcznie zapiszesz zmieniony plik (np. Używając Ctrl + S lub cmd + S). Wydaje się, że nie działa z automatycznym zapisywaniem.

Hubert Grzeskowiak
źródło
Potwierdzam, że tak jest również w przypadku PyCharm.
tsando
0

W notesach Jupyter na Anaconda:

%load_ext autoreload
%autoreload 2

wyprodukował wiadomość:

Rozszerzenie automatycznego przeładowania jest już załadowane. Aby go ponownie załadować, użyj: %reload_ext autoreload

Wygląda na to, że lepiej zrobić:

%reload_ext autoreload
%autoreload 2

Informacje o wersji:

Wersja serwera notebooków to 5.0.0 i działa na: Python 3.6.2 | Anaconda, Inc. | (domyślnie, 20 września 2017 r., 13:35:58) [MSC v.1900 32-bitowy (Intel)]

z góry dziękuję
źródło
0

Żadne podobiekty nie zostaną przez to ponownie załadowane, uważam, że musisz do tego użyć głębokiego przeładowania IPython.

aoeu256
źródło