Ponownie zaimportuj moduł w Pythonie, gdy jest interaktywny

382

Wiem, że da się to zrobić, ale nigdy nie pamiętam jak.

Jak możesz ponownie zaimportować moduł w Pythonie? Scenariusz wygląda następująco: importuję moduł interaktywnie i majstruje przy nim, ale potem napotyka błąd. Naprawiam błąd w pliku .py, a następnie chcę ponownie zaimportować naprawiony moduł bez wychodzenia z Pythona. Jak mogę to zrobić ?

Stefano Borini
źródło

Odpowiedzi:

368

To powinno działać:

reload(my.module)

Z dokumentacji Pythona

Załaduj ponownie wcześniej zaimportowany moduł. Argument musi być obiektem modułu, więc musiał zostać wcześniej pomyślnie zaimportowany. Jest to przydatne, jeśli edytowałeś plik źródłowy modułu za pomocą zewnętrznego edytora i chcesz wypróbować nową wersję bez wychodzenia z interpretera Pythona.

Jeśli korzystasz z Python 3.4 i nowszych, zrób import importlib, a następnie zrób importlib.reload(nameOfModule).

Nie zapomnij o zastrzeżeniach dotyczących tej metody:

  • Po ponownym załadowaniu modułu jego słownik (zawierający zmienne globalne modułu) zostaje zachowany. Ponowne zdefiniowanie nazw zastąpi stare definicje, więc ogólnie nie stanowi to problemu, ale jeśli nowa wersja modułu nie definiuje nazwy zdefiniowanej przez starą wersję, stara definicja nie jest usuwana.

  • Jeśli moduł importuje obiekty z innego modułu za pomocą from ... import ..., wywołanie reload()drugiego modułu nie przedefiniuje obiektów importowanych z niego - jednym z nich jest ponowne wykonanie frominstrukcji, innym zamiast nich jest użycie importnazw kwalifikowanych ( module.*name*).

  • Jeśli moduł tworzy instancje klasy, przeładowanie modułu, który definiuje klasę, nie wpływa na definicje metod instancji - nadal używają starej definicji klasy. To samo dotyczy klas pochodnych.

Benjamin Wohlwend
źródło
26
jeśli załaduję moduły za pomocą from filename import *. Jak przeładować?
Peter Zhu,
@PeterZhu w przypadku „z mod import fcn” obiekt modułu nie jest dodawany do przestrzeni nazw. Musisz więc jawnie zaimportować moduł, aby móc go później ponownie załadować. import foo; from foo import bar; reload(foo)
Ted
Próbowałem przeładowania, a także magii automatycznego przeładowania i widzę, że mój kod został odzwierciedlony w stosie komunikatu o błędzie, ale sam błąd nadal wydaje się być nieaktualny (np. Linia błędu jest dokładnie taka sama wiersz jak poprzednio, który zmieniłem na komentarz, a komentarz wyraźnie nie może powodować błędów). Mój moduł jest załadowany jako rozszerzenie Jupyter. Czy ktoś może wiedzieć, czy wymaga to innej pracy? Dzięki!
yifanwu
1
Jeśli funkcja została zaimportowana jako „import mod as name”, musisz wykonać następujące czynności: „import importlib importlib.reload (name)”
Noe
Ta metoda nie może przesłonić odniesień innych modułów do ponownie załadowanego modułu. Zobacz stackoverflow.com/a/61617169/2642356, aby znaleźć rozwiązanie tego problemu.
EZLearner
287

W Pythonie 3 reloadnie jest już funkcją wbudowaną.

Jeśli używasz Python 3.4+, powinieneś użyć reloadz importlibbiblioteki:

import importlib
importlib.reload(some_module)

Jeśli używasz Pythona 3.2 lub 3.3, powinieneś:

import imp  
imp.reload(module)  

zamiast. Zobacz http://docs.python.org/3.0/library/imp.html#imp.reload

Jeśli używasz ipython, zdecydowanie rozważ użycie autoreloadrozszerzenia:

%load_ext autoreload
%autoreload 2
Andrzej
źródło
Mimo że w Pythonie 2 napisano dużo kodu Pythona, Python 3 staje się coraz bardziej opłacalną opcją z każdym dniem. Dzięki za wskazówkę!
Aaron Johnson
40
imp.reloadjest przestarzałe od Python 3.4, zamiast tego użyj importlib.reloadfunkcji .
jfs,
1
@Andrew dzięki! Użyłem% autoreload, to wspaniale, moje już utworzone obiekty otrzymały automatycznie poprawioną implementację metod klasy bez konieczności ich ponownego tworzenia
jeanmi
4
Jestem trochę późno, ale myślę, że to nie działa, jeśli to, czego potrzebujesz, aby przeładować jest funkcją lub klasy z poziomu modułu: jeśli import statment było from mymodule import myfunc, to importlib.reload(myfunc), importlib.reload(mymodule.myfunc), importlib.reload(mymodule)wszystkie dają NameError.
Puff
@Puff zobacz moją odpowiedź poniżej, aby dowiedzieć się, jak ponownie zaimportować funkcję
jss367
46

W rzeczywistości w Pythonie 3 moduł impjest oznaczony jako DEPRECATED. Przynajmniej tak jest w przypadku 3.4.

Zamiast tego należy użyć reloadfunkcji z importlibmodułu:

https://docs.python.org/3/library/importlib.html#importlib.reload

Należy jednak pamiętać, że w tej bibliotece wprowadzono pewne zmiany interfejsu API w dwóch ostatnich mniejszych wersjach.

funky-future
źródło
5

Jeśli chcesz zaimportować określoną funkcję lub klasę z modułu, możesz to zrobić:

import importlib
import sys
importlib.reload(sys.modules['my_module'])
from my_module import my_function
jss367
źródło
0

Mimo że podane odpowiedzi działają dla określonego modułu, nie załadują ponownie podmodułów, jak zauważono w tej odpowiedzi :

Jeśli moduł importuje obiekty z innego modułu za pomocą from ... import ..., wywołanie reload()innego modułu nie przedefiniuje obiektów importowanych z niego - jednym z nich jest ponowne wykonanie instrukcji from, innym jest użycie importi kwalifikowane nazwy ( module.*name*).

Jeśli jednak używasz __all__zmiennej do zdefiniowania publicznego API, możliwe jest automatyczne przeładowanie wszystkich publicznie dostępnych modułów:

# Python >= 3.5
import importlib
import types


def walk_reload(module: types.ModuleType) -> None:
    if hasattr(module, "__all__"):
        for submodule_name in module.__all__:
            walk_reload(getattr(module, submodule_name))
    importlib.reload(module)


walk_reload(my_module)

Zastrzeżenia odnotowane w poprzedniej odpowiedzi są jednak nadal aktualne. W szczególności na modyfikację podmodułu, który nie jest częścią publicznego API, jak opisano w __all__zmiennej, nie będzie miało wpływu przeładowanie za pomocą tej funkcji. Podobnie usunięcie elementu submodułu nie zostanie odzwierciedlone przez przeładowanie.

skasch
źródło