Mam długo działający serwer Python i chciałbym móc uaktualnić usługę bez ponownego uruchamiania serwera. Jak najlepiej to zrobić?
if foo.py has changed:
unimport foo <-- How do I do this?
import foo
myfoo = foo.Foo()
python
module
reload
python-import
Mark Harrison
źródło
źródło
Odpowiedzi:
Możesz ponownie załadować moduł, gdy został już zaimportowany za pomocą
reload
wbudowanej funkcji (tylko Python 3.4+) :W Pythonie 3
reload
został przeniesiony doimp
modułu. W 3.4imp
został wycofany na korzyśćimportlib
ireload
został dodany do tego ostatniego. W przypadku kierowania na wersję 3 lub nowszą odwołaj się do odpowiedniego modułu podczas jego wywoływaniareload
lub importuj go.Myślę, że tego właśnie chcesz. Serwery WWW, takie jak serwer programistyczny Django, używają tego, aby można było zobaczyć efekty zmian kodu bez ponownego uruchamiania samego procesu serwera.
Cytując z dokumentów:
Jak zauważyłeś w swoim pytaniu, będziesz musiał zrekonstruować
Foo
obiekty, jeśliFoo
klasa znajduje się wfoo
module.źródło
X
nie jest modułem, możeszimport sys; reload(sys.modules[X.__module__])
is_changed
funkcja jest po prostu dowolną funkcją, którą należy napisać; to nie jest wbudowane. Na przykład może otworzyć plik odpowiadający importowanemu modułowi i różnicować go w wersji buforowanej, aby sprawdzić, czy się zmienił.W Python 3.0–3.3 użyłbyś:
imp.reload(module)
BDFL nie odpowiedział na to pytanie.
Jednak
imp
został wycofany w wersji 3.4 na rzeczimportlib
(dzięki @Stefan! ).I myślę więc, że teraz używać
importlib.reload(module)
, choć nie jestem pewien.źródło
reload(__builtins__)
obowiązuje w 2.xUsunięcie modułu może być szczególnie trudne, jeśli nie jest to czysty Python.
Oto kilka informacji z: Jak naprawdę usunąć zaimportowany moduł?
źródło
setattr(package, "empty", None)
reload()
ponownie ładuje tylko najwyższy moduł, a wszystko w nim nie zostanie ponownie załadowane, chyba że najpierw usuniesz go z sys.modules.reload(module)
, ale tylko wtedy, gdy jest całkowicie samodzielny. Jeśli cokolwiek innego ma odniesienie do modułu (lub dowolnego obiektu należącego do modułu), to dostaniesz subtelne i ciekawe błędy spowodowane przez stary kod zawieszający się dłużej niż się spodziewałeś, i rzeczy takie jakisinstance
niedziałanie w różnych wersjach ten sam kod.Jeśli masz zależności jednokierunkowe, musisz także ponownie załadować wszystkie moduły zależne od ponownie załadowanego modułu, aby pozbyć się wszystkich odniesień do starego kodu. A następnie rekurencyjnie przeładuj moduły zależne od przeładowanych modułów.
Jeśli masz zależności cykliczne, co jest bardzo częste, na przykład podczas przeładowywania pakietu, musisz rozładować wszystkie moduły w grupie za jednym razem. Nie możesz tego zrobić,
reload()
ponieważ będzie ponownie importować każdy moduł, zanim jego zależności zostaną odświeżone, pozwalając starym referencjom wkradać się do nowych modułów.Jedynym sposobem na zrobienie tego w tym przypadku jest włamanie
sys.modules
, które jest trochę nieobsługiwane. Musiałbyś przejść i usunąć każdysys.modules
wpis, który chcesz załadować ponownie przy następnym imporcie, a także usunąć wpisy, których wartościNone
dotyczą problemu z implementacją związanego z buforowaniem nieudanych importów względnych. Nie jest to strasznie miłe, ale dopóki masz w pełni samodzielny zestaw zależności, które nie pozostawiają referencji poza bazą kodu, jest to wykonalne.Prawdopodobnie najlepiej zrestartować serwer. :-)
źródło
None
wartościami, ponieważ właśnie wpadam na ten problem: usuwam elementy zsys.modules
i po ponownym zaimportowaniu niektórych importowanych zależnościNone
.None
wpisy zdołały wrócić z powrotem przez mechanizm importu po usunięciu „prawdziwych” wpisów, i wydaje mi się, że nie mogę tego zrobić w wersji 2.7; w przyszłości z pewnością nie będzie to już problemem, ponieważ ukryty import względny zniknął. Tymczasem usunięcie wszystkich wpisów zNone
wartością wydaje się to naprawić.reload
funkcję? Jest wbudowany, nie musisz importować żadnej biblioteki.źródło
nose.run()
, nawet poreload(my_module)
%run my_module
[del(sys.modules[mod] for mod in sys.modules.keys() if mod.startswith('myModule.')]
.import sys; import json; del sys.modules['json']; print(json.dumps([1]))
i moduł json nadal działa, mimo że nie ma go już w sys.modules.W przypadku Python 2 użyj wbudowanej funkcji reload () :
W przypadku Python 2 i 3.2–3.3 użyj przeładowania z modułu imp :
Ale
imp
jest przestarzałe od wersji 3.4 na korzyść importlib , więc użyj:lub
źródło
from six import reload_module
(pip install six
najpierw trzeba )from six.moves import reload_module
( doc )Poniższy kod pozwala na kompatybilność z Python 2/3:
Możesz go używać tak jak
reload()
w obu wersjach, co upraszcza sprawę .źródło
Akceptowana odpowiedź nie obsługuje przypadku Y z importu X. Ten kod obsługuje go również i standardowy przypadek importu:
W przypadku przeładowania ponownie przypisujemy nazwy najwyższego poziomu do wartości przechowywanych w nowo załadowanym module, który je aktualizuje.
źródło
>>> from X import Y
przeładowaniu wykonaj>>> __import__('X', fromlist='Y')
fromlist='*'
?from
w instrukcjach importu. Wystarczy surowyimport <package>
i jawny pakiet.symbol w kodzie. Zrozum, że nie zawsze jest to możliwe lub pożądane. (Oto jeden wyjątek: z przyszłego importu print_function.)foo = reload(foo); from foo import *
Jest to nowoczesny sposób ponownego ładowania modułu:
Jeśli chcesz obsługiwać wersje Pythona starsze niż 3.5, spróbuj tego:
Aby go użyć, uruchom
reload(MODULE)
, zastępującMODULE
moduł, który chcesz ponownie załadować.Na przykład
reload(math)
przeładujemath
moduł.źródło
from importlib import reload
. To możesz zrobićreload(MODULE_NAME)
. Nie ma potrzeby korzystania z tej funkcji.modulereload(MODULE_NAME)
jest bardziej zrozumiałe niż tylkoreload(MODULE_NAME)
i ma mniejszą szansę na konflikt z innymi funkcjami.Jeśli jesteś nie na serwerze, ale rozwija i trzeba często przeładować moduł, oto miły wskazówka.
Po pierwsze, upewnij się, że używasz doskonałej powłoki IPython z projektu Jupyter Notebook. Po zainstalowaniu Jupytera możesz go uruchomić z
ipython
, lubjupyter console
nawet lepiejjupyter qtconsole
, co da ładną kolorową konsolę z uzupełnianiem kodu w dowolnym systemie operacyjnym.Teraz w swojej powłoce wpisz:
Teraz, każdym razem , gdy uruchomisz skrypt, moduły zostaną ponownie załadowane.
Poza tym
2
istnieją inne opcje magii automatycznego przeładowania :źródło
Dla tych jak ja, którzy chcą zwolnić wszystkie moduły (gdy są uruchomione w interpretera Pythona pod Emacsem ):
Więcej informacji znajduje się w Przeładowywanie modułów Python .
źródło
sys.modules.values()
module jest modułem. Na przykład: >>> type (sys.modules.values () [1]) <class 'email.LazyImporter'> Więc jeśli spróbuję uruchomić ten kod, to on się przewraca (wiem, że nie jest to praktyczne rozwiązanie, po prostu wskazując to).if mod and mod.__name__ != "__main__": imp.reload(mod)
Enthought Traits ma moduł, który działa dość dobrze w tym celu. https://traits.readthedocs.org/en/4.3.0/_modules/traits/util/refresh.html
Przeładuje każdy moduł, który został zmieniony, i zaktualizuje inne moduły i obiekty, które go używają. Przez większość czasu nie działa z
__very_private__
metodami i może dusić dziedziczenie klas, ale oszczędza mi szalonej ilości czasu od konieczności ponownego uruchamiania aplikacji hosta podczas pisania GUI PyQt lub rzeczy, które działają w programach takich jak Maya lub Nuke. Nie działa to może 20-30% czasu, ale nadal jest niezwykle pomocne.Pakiet Enthought nie przeładowuje plików w momencie ich zmiany - musisz to nazwać jawnie - ale nie powinno to być takie trudne do wdrożenia, jeśli naprawdę tego potrzebujesz
źródło
Ci, którzy używają Pythona 3 i przeładowują z importlib.
Jeśli masz problemy, jak się wydaje, moduł nie ładuje się ponownie ... To dlatego, że potrzebuje trochę czasu, aby ponownie skompilować pyc (do 60 sekund). Piszę tę wskazówkę tylko, że wiesz, czy doświadczyłeś tego rodzaju problemu.
źródło
01.02.2018
foo
musi zostać wcześniej pomyślnie zaimportowany.from importlib import reload
,reload(foo)
31,5 importlib - Implementacja importu - dokumentacja Python 3.6.4
źródło
Inna opcja. Zobacz, że domyślne ustawienie Python
importlib.reload
po prostu ponownie zaimportuje bibliotekę przekazaną jako argument. To nie będzie ponownie załadować bibliotek importowania lib. Jeśli zmieniłeś wiele plików i masz nieco skomplikowany pakiet do zaimportowania, musisz dokonać głębokiego przeładowania .Jeśli masz zainstalowany IPython lub Jupyter , możesz użyć funkcji do głębokiego przeładowania wszystkich bibliotek:
Jeśli nie masz Jupytera, zainstaluj go za pomocą tego polecenia w powłoce:
źródło
reload() argument must be module
. Korzystam z importu funkcji niestandardowej i wydaje się, że nie działa. Korzystanie z wbudowanych modułów działa. :-( to strata czasu będąc przeładunku ipython dla każdej małej zmiany zrobiłem do mojego kodu ...Edycja (odpowiedź V2)
Rozwiązanie z przeszłości jest dobre tylko do uzyskania informacji o resecie, ale nie zmieni wszystkich odniesień (więcej niż,
reload
ale mniej niż wymagane). Aby faktycznie ustawić wszystkie referencje, musiałem wejść do śmietnika i przepisać tam referencje. Teraz działa jak urok!Zauważ, że to nie zadziała, jeśli GC jest wyłączony lub jeśli przeładowywanie danych nie jest monitorowane przez GC. Jeśli nie chcesz zadzierać z GC, oryginalna odpowiedź może ci wystarczyć.
Nowy kod:
Oryginalna odpowiedź
Jak napisano w odpowiedzi @ bobince, jeśli istnieje już odwołanie do tego modułu w innym module (zwłaszcza jeśli zostało ono zaimportowane przy użyciu
as
słowa kluczowego podobnegoimport numpy as np
), to wystąpienie nie zostanie zastąpione.Okazało się to dla mnie dość problematyczne, gdy stosowałem testy, które wymagały stanu „czyszczenia” modułów konfiguracyjnych, więc napisałem funkcję o nazwie,
reset_module
która korzystaimportlib
zreload
funkcji i rekurencyjnie zastępuje wszystkie zadeklarowane atrybuty modułu. Został przetestowany z Pythonem w wersji 3.6.Uwaga: używaj ostrożnie! Używanie ich w modułach nieperyferyjnych (na przykład modułach, które definiują klasy używane zewnętrznie) może prowadzić do wewnętrznych problemów w Pythonie (takich jak problemy z wytrawianiem / usuwaniem wytrawiania).
źródło
dla mnie w przypadku Abaqus jest to sposób, w jaki działa. Wyobraź sobie, że Twój plik to Class_VerticesEdges.py
źródło
Mam problem z przeładowaniem czegoś w Sublime Text, ale w końcu mogłem napisać to narzędzie do przeładowania modułów w Sublime Text na podstawie kodu
sublime_plugin.py
używanego do przeładowywania modułów.Poniżej akceptujesz przeładowanie modułów ze ścieżek ze spacjami na ich nazwach, a następnie po przeładowaniu możesz po prostu zaimportować, jak zwykle.
Jeśli uruchomisz po raz pierwszy, powinno to załadować moduł, ale jeśli później będziesz mógł ponownie zastosować metodę / funkcję
run_tests()
, ponownie załaduje pliki testowe. Z Sublime Text (Python 3.3.6
) zdarza się to często, ponieważ jego tłumacz nigdy się nie zamyka (chyba że uruchomisz ponownie Sublime Text, tj.Python3.3
Interpreter).źródło
Innym sposobem może być zaimportowanie modułu do funkcji. W ten sposób po zakończeniu funkcji moduł zostanie wyrzucony śmieci.
źródło
sys.modules
.