Jak rozładować (ponownie załadować) moduł?

797

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()
Mark Harrison
źródło
53
Wskazówka: „import” nie oznacza „załaduj”, oznacza „załaduj, jeśli jeszcze nie został załadowany, a następnie zaimportuj do przestrzeni nazw”.
Kos,
3
pytanie nie powinno zawierać „rozładowania”, ponieważ nie jest to jeszcze możliwe w pythonie - przeładowanie jest jednak znanym paradygmatem, jak podano poniżej
robertmoggach
Miałem ten sam problem podczas korzystania z modułu dynamicznego w aplikacji py2exe. Ponieważ py2exe zawsze trzyma kod bajtowy w katalogu zip, przeładowanie nie działało. Ale znalazłem działające rozwiązanie za pomocą modułu import_file. Teraz moja aplikacja działa dobrze.
Pritam Pan
2
Co zrobić, jeśli chcesz „zwolnić”, ponieważ kod próbuje użyć pliku .pyc?
darkgaze

Odpowiedzi:

788

Możesz ponownie załadować moduł, gdy został już zaimportowany za pomocą reloadwbudowanej funkcji (tylko Python 3.4+) :

from importlib import reload  
import foo

while True:
    # Do some things.
    if is_changed(foo):
        foo = reload(foo)

W Pythonie 3 reloadzostał przeniesiony do impmodułu. W 3.4 impzostał wycofany na korzyść importlibi reloadzostał dodany do tego ostatniego. W przypadku kierowania na wersję 3 lub nowszą odwołaj się do odpowiedniego modułu podczas jego wywoływania reloadlub 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:

Kod modułów Pythona jest ponownie kompilowany, a kod na poziomie modułu ponownie wykonywany, definiując nowy zestaw obiektów, które są powiązane z nazwami w słowniku modułu. Funkcja init modułów rozszerzeń nie jest wywoływana po raz drugi. Podobnie jak w przypadku wszystkich innych obiektów w Pythonie, stare obiekty są odzyskiwane dopiero po tym, jak ich liczba referencji spadnie do zera. Nazwy w przestrzeni nazw modułów są aktualizowane, aby wskazywały na nowe lub zmienione obiekty. Inne odniesienia do starych obiektów (takie jak nazwy zewnętrzne modułu) nie są powiązane w odniesieniu do nowych obiektów i muszą być aktualizowane w każdej przestrzeni nazw, w której występują, jeśli jest to pożądane.

Jak zauważyłeś w swoim pytaniu, będziesz musiał zrekonstruować Fooobiekty, jeśli Fooklasa znajduje się w foomodule.

cdleary
źródło
10
tak naprawdę serwer dev Django uruchamia się ponownie po zmianie pliku .. (restartuje serwer, a nie tylko ponownie ładuje moduł)
hasen 13.01.2009
25
skąd pochodzi ta funkcja „is_changed”? nie widzę w nim dokumentacji i nie działa w moim środowisku Python 3.1.3, ani nie działa w 2.6.4.
jedmao
5
bez żadnych ograniczeń, Django nie może po prostu użyć przeładowania: pyunit.sourceforge.net/notes/reloading.html
raylu 5'12
14
@BartoszKP jeśli Xnie jest modułem, możeszimport sys; reload(sys.modules[X.__module__])
drevicko 16.04.16
5
@jedmao @JamesDraper Jestem pewien, że ta is_changedfunkcja 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ł.
James Mchugh,
252

W Python 3.0–3.3 użyłbyś: imp.reload(module)

BDFL nie odpowiedział na to pytanie.

Jednak impzostał 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.

Paul D. Waite
źródło
23
Szczery nowicjusz jest wdzięczny za informacje o krytycznych niuansach między Pythonem 2 a 3.
Smandoli
24
czy imp.reload (imp) jest ważny?
Loïc Faure-Lacroix,
2
@ LoïcFaure-Lacroix ten sam sposób reload(__builtins__)obowiązuje w 2.x
JBernardo
1
@ Tarrasch: to moduł Pythona, który chcesz ponownie załadować, jak w przykładzie w pytaniu.
Paul D. Waite,
3
@ LoïcFaure-Lacroix tak, imp może przeładować się.
Devyn Collier Johnson
92

Usunię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ł?

Możesz użyć sys.getrefcount (), aby znaleźć rzeczywistą liczbę referencji.

>>> import sys, empty, os
>>> sys.getrefcount(sys)
9
>>> sys.getrefcount(os)
6
>>> sys.getrefcount(empty)
3

Liczby większe niż 3 wskazują, że trudno będzie się pozbyć modułu. Własny moduł „pusty” (nie zawierający niczego) powinien zostać później wyrzucony

>>> del sys.modules["empty"]
>>> del empty

ponieważ trzecie odniesienie jest artefaktem funkcji getrefcount ().

Gregg Lind
źródło
4
Właśnie odkryłem, że jeśli moduł jest częścią pakietu, musisz go również tam usunąć:setattr(package, "empty", None)
u0b34a0f6ae
6
To prawidłowe rozwiązanie, szczególnie jeśli masz pakiet z zagnieżdżonymi modułami. reload()ponownie ładuje tylko najwyższy moduł, a wszystko w nim nie zostanie ponownie załadowane, chyba że najpierw usuniesz go z sys.modules.
Cerin,
73

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 jak isinstanceniedział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żdy sys.moduleswpis, który chcesz załadować ponownie przy następnym imporcie, a także usunąć wpisy, których wartości Nonedotyczą 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. :-)

Bobin
źródło
1
Czy dreload nie jest specjalnie dla tego scenariusza?
Josh
@Josh: nie, służy do przeładowywania drzewa pakietów, a nawet wtedy działa tylko tak długo, jak pakiet nie ma zależności zewnętrznych / kołowych.
bobince
1
Czy możesz opracować część z Nonewartościami, ponieważ właśnie wpadam na ten problem: usuwam elementy z sys.modulesi po ponownym zaimportowaniu niektórych importowanych zależności None.
schlamar
@shclamar: Zobacz stackoverflow.com/questions/1958417/… (i linki z tego miejsca) w celu uzyskania tła. Nie jest dla mnie jasne (nawet patrząc na kod import.c), w jaki sposób Nonewpisy 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 z Nonewartością wydaje się to naprawić.
bobince
1
@Eliethesaiyan: masz na myśli reloadfunkcję? Jest wbudowany, nie musisz importować żadnej biblioteki.
bobince
63
if 'myModule' in sys.modules:  
    del sys.modules["myModule"]
Kumaresan
źródło
3
+1. Moim celem było przeprowadzenie testów nosa w Pythonie. Po załadowaniu modułu i zmianie nazwy niektórych funkcji stare nazwy pozostały podczas wywoływania nose.run(), nawet poreload(my_module) %run my_module
Peter D
5
Jeśli moduł importuje własne submoduły, może być konieczne ich usunięcie. Coś jak [del(sys.modules[mod] for mod in sys.modules.keys() if mod.startswith('myModule.')].
drevicko
Nie sądzę, że to zwalnia moduł. W Pythonie 3.8: 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.
Seperman
60

W przypadku Python 2 użyj wbudowanej funkcji reload () :

reload(module)

W przypadku Python 2 i 3.2–3.3 użyj przeładowania z modułu imp :

import imp
imp.reload(module)

Ale imp jest przestarzałe od wersji 3.4 na korzyść importlib , więc użyj:

import importlib
importlib.reload(module)

lub

from importlib import reload
reload(module)
Goetzc
źródło
2
aby poradzić sobie z którymkolwiek z tych przypadków: from six import reload_module( pip install sixnajpierw trzeba )
Anentropic
@Anentropic: Zaleca się używanie sześciu pakietów, ale składnia to from six.moves import reload_module( doc )
x0s
23

Poniższy kod pozwala na kompatybilność z Python 2/3:

try:
    reload
except NameError:
    # Python 3
    from imp import reload

Możesz go używać tak jak reload()w obu wersjach, co upraszcza sprawę .

Matt Clarkson
źródło
18

Akceptowana odpowiedź nie obsługuje przypadku Y z importu X. Ten kod obsługuje go również i standardowy przypadek importu:

def importOrReload(module_name, *names):
    import sys

    if module_name in sys.modules:
        reload(sys.modules[module_name])
    else:
        __import__(module_name, fromlist=names)

    for name in names:
        globals()[name] = getattr(sys.modules[module_name], name)

# use instead of: from dfly_parser import parseMessages
importOrReload("dfly_parser", "parseMessages")

W przypadku przeładowania ponownie przypisujemy nazwy najwyższego poziomu do wartości przechowywanych w nowo załadowanym module, który je aktualizuje.

Joseph Garvin
źródło
Zauważyłem problem, globals () odnosi się do modułu, w którym definiujesz tę funkcję, więc jeśli zdefiniujesz ją w module innym niż ten, w którym ją wywołujesz, to nie działa.
Joseph Garvin
Dla interaktywnych, po >>> from X import Yprzeładowaniu wykonaj>>> __import__('X', fromlist='Y')
Bob Stein
@ BobStein-VisiBone, czy istnieje sposób, aby to zadziałało, kiedy fromlist='*'?
Mike C
Dobre pytanie, nie wiem @MikeC. Nawiasem mówiąc, mam tendencję do zaprzestania prawie wszystkich zastosowań fromw instrukcjach importu. Wystarczy surowy import <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.)
Bob Stein
Mike C: dla mnie działafoo = reload(foo); from foo import *
szalenie
16

Jest to nowoczesny sposób ponownego ładowania modułu:

from importlib import reload

Jeśli chcesz obsługiwać wersje Pythona starsze niż 3.5, spróbuj tego:

from sys import version_info
if version_info[0] < 3:
    pass # Python 2 has built in reload
elif version_info[0] == 3 and version_info[1] <= 4:
    from imp import reload # Python 3.0 - 3.4 
else:
    from importlib import reload # Python 3.5+

Aby go użyć, uruchom reload(MODULE), zastępując MODULEmoduł, który chcesz ponownie załadować.

Na przykład reload(math)przeładuje mathmoduł.

Richie Bendall
źródło
4
Albo po prostu zrób from importlib import reload. To możesz zrobić reload(MODULE_NAME). Nie ma potrzeby korzystania z tej funkcji.
paul
Uważam, że modulereload(MODULE_NAME)jest bardziej zrozumiałe niż tylko reload(MODULE_NAME)i ma mniejszą szansę na konflikt z innymi funkcjami.
Richie Bendall
@RichieBendall Przepraszamy, ale ta odpowiedź jest całkowicie błędna. Funkcja reload () pobiera obiekt modułu, a nie nazwę modułu ... Przeczytaj dokumentację: docs.python.org/3/library/importlib.html#importlib.reload I zgadzam się z @ pault - to „as modulereload” jest zbędne .
mbdevpl
Zmieniłem odpowiedź, aby odzwierciedlić Twoją opinię.
Richie Bendall
13

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, lub jupyter consolenawet lepiej jupyter qtconsole, co da ładną kolorową konsolę z uzupełnianiem kodu w dowolnym systemie operacyjnym.

Teraz w swojej powłoce wpisz:

%load_ext autoreload
%autoreload 2

Teraz, każdym razem , gdy uruchomisz skrypt, moduły zostaną ponownie załadowane.

Poza tym 2istnieją inne opcje magii automatycznego przeładowania :

%autoreload
Reload all modules (except those excluded by %aimport) automatically now.

%autoreload 0
Disable automatic reloading.

%autoreload 1
Reload all modules imported with %aimport every time before executing the Python code typed.

%autoreload 2
Reload all modules (except those excluded by %aimport) every time before
executing the Python code typed.
Neves
źródło
7

Dla tych jak ja, którzy chcą zwolnić wszystkie moduły (gdy są uruchomione w interpretera Pythona pod Emacsem ):

   for mod in sys.modules.values():
      reload(mod)

Więcej informacji znajduje się w Przeładowywanie modułów Python .

Peter Mortensen
źródło
W rzeczywistości nie wydaje się to działać niezawodnie (w wersji 2.6), ponieważ nie wszystko w 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).
Francis Davey,
Nie działa nawet we wcześniejszych pytonach - jak napisano. Musiałem wykluczyć niektóre nazwiska. Zaktualizuję wiadomość po przeniesieniu tego kodu na nowy komputer.
2
Działa dobrze w Pythonie 2.7 po pewnych modyfikacjach:if mod and mod.__name__ != "__main__": imp.reload(mod)
Czarek Tomczak,
2
Działa to dla mnie dobrze: import imp [reload (m) for m in sys.modules.values ​​() if mi not not " " in m .__ name and not imp.is_builtin (m .__ name__)]
Patrick Wolf
5

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

flipthefrog
źródło
5

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.

PythonMan
źródło
3

Inna opcja. Zobacz, że domyślne ustawienie Python importlib.reloadpo 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:

from IPython.lib.deepreload import reload as dreload
dreload(foo)

Jeśli nie masz Jupytera, zainstaluj go za pomocą tego polecenia w powłoce:

pip3 install jupyter
Neves
źródło
Zarówno ten Ipython dreload, jak i reload () z importlib narzekają 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 ...
m3nda
2

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ż, reloadale 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:

import importlib
import inspect
import gc
from weakref import ref


def reset_module(module, inner_modules_also=True):
    """
    This function is a stronger form of importlib's `reload` function. What it does, is that aside from reloading a
    module, it goes to the old instance of the module, and sets all the (not read-only) attributes, functions and classes
    to be the reloaded-module's
    :param module: The module to reload (module reference, not the name)
    :param inner_modules_also: Whether to treat ths module as a package as well, and reload all the modules within it.
    """

    # For the case when the module is actually a package
    if inner_modules_also:
        submods = {submod for _, submod in inspect.getmembers(module)
                   if (type(submod).__name__ == 'module') and (submod.__package__.startswith(module.__name__))}
        for submod in submods:
            reset_module(submod, True)

    # First, log all the references before reloading (because some references may be changed by the reload operation).
    module_tree = _get_tree_references_to_reset_recursively(module, module.__name__)

    new_module = importlib.reload(module)
    _reset_item_recursively(module, module_tree, new_module)


def _update_referrers(item, new_item):
    refs = gc.get_referrers(item)

    weak_ref_item = ref(item)
    for coll in refs:
        if type(coll) == dict:
            enumerator = coll.keys()
        elif type(coll) == list:
            enumerator = range(len(coll))
        else:
            continue

        for key in enumerator:

            if weak_ref_item() is None:
                # No refs are left in the GC
                return

            if coll[key] is weak_ref_item():
                coll[key] = new_item

def _get_tree_references_to_reset_recursively(item, module_name, grayed_out_item_ids = None):
    if grayed_out_item_ids is None:
        grayed_out_item_ids = set()

    item_tree = dict()
    attr_names = set(dir(item)) - _readonly_attrs
    for sub_item_name in attr_names:

        sub_item = getattr(item, sub_item_name)
        item_tree[sub_item_name] = [sub_item, None]

        try:
            # Will work for classes and functions defined in that module.
            mod_name = sub_item.__module__
        except AttributeError:
            mod_name = None

        # If this item was defined within this module, deep-reset
        if (mod_name is None) or (mod_name != module_name) or (id(sub_item) in grayed_out_item_ids) \
                or isinstance(sub_item, EnumMeta):
            continue

        grayed_out_item_ids.add(id(sub_item))
        item_tree[sub_item_name][1] = \
            _get_tree_references_to_reset_recursively(sub_item, module_name, grayed_out_item_ids)

    return item_tree


def _reset_item_recursively(item, item_subtree, new_item):

    # Set children first so we don't lose the current references.
    if item_subtree is not None:
        for sub_item_name, (sub_item, sub_item_tree) in item_subtree.items():

            try:
                new_sub_item = getattr(new_item, sub_item_name)
            except AttributeError:
                # The item doesn't exist in the reloaded module. Ignore.
                continue

            try:
                # Set the item
                _reset_item_recursively(sub_item, sub_item_tree, new_sub_item)
            except Exception as ex:
                pass

    _update_referrers(item, new_item)

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 assłowa kluczowego podobnego import 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_modulektóra korzysta importlibz reloadfunkcji i rekurencyjnie zastępuje wszystkie zadeklarowane atrybuty modułu. Został przetestowany z Pythonem w wersji 3.6.

import importlib
import inspect
from enum import EnumMeta

_readonly_attrs = {'__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__',
               '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__func__', '__ge__', '__get__',
               '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__',
               '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__',
               '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__',
               '__subclasshook__', '__weakref__', '__members__', '__mro__', '__itemsize__', '__isabstractmethod__',
               '__basicsize__', '__base__'}


def reset_module(module, inner_modules_also=True):
    """
    This function is a stronger form of importlib's `reload` function. What it does, is that aside from reloading a
    module, it goes to the old instance of the module, and sets all the (not read-only) attributes, functions and classes
    to be the reloaded-module's
    :param module: The module to reload (module reference, not the name)
    :param inner_modules_also: Whether to treat ths module as a package as well, and reload all the modules within it.
    """

    new_module = importlib.reload(module)

    reset_items = set()

    # For the case when the module is actually a package
    if inner_modules_also:
        submods = {submod for _, submod in inspect.getmembers(module)
                   if (type(submod).__name__ == 'module') and (submod.__package__.startswith(module.__name__))}
        for submod in submods:
            reset_module(submod, True)

    _reset_item_recursively(module, new_module, module.__name__, reset_items)


def _reset_item_recursively(item, new_item, module_name, reset_items=None):
    if reset_items is None:
        reset_items = set()

    attr_names = set(dir(item)) - _readonly_attrs

    for sitem_name in attr_names:

        sitem = getattr(item, sitem_name)
        new_sitem = getattr(new_item, sitem_name)

        try:
            # Set the item
            setattr(item, sitem_name, new_sitem)

            try:
                # Will work for classes and functions defined in that module.
                mod_name = sitem.__module__
            except AttributeError:
                mod_name = None

            # If this item was defined within this module, deep-reset
            if (mod_name is None) or (mod_name != module_name) or (id(sitem) in reset_items) \
                    or isinstance(sitem, EnumMeta):  # Deal with enums
                continue

            reset_items.add(id(sitem))
            _reset_item_recursively(sitem, new_sitem, module_name, reset_items)
        except Exception as ex:
            raise Exception(sitem_name) from ex

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

EZLearner
źródło
1

dla mnie w przypadku Abaqus jest to sposób, w jaki działa. Wyobraź sobie, że Twój plik to Class_VerticesEdges.py

sys.path.append('D:\...\My Pythons')
if 'Class_VerticesEdges' in sys.modules:  
    del sys.modules['Class_VerticesEdges']
    print 'old module Class_VerticesEdges deleted'
from Class_VerticesEdges import *
reload(sys.modules['Class_VerticesEdges'])
Matt S.
źródło
Ta odpowiedź jest bezpośrednią kopią stąd: ebanshi.cc/questions/1942/…
SiHa,
0

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.pyuż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.

def reload_module(full_module_name):
    """
        Assuming the folder `full_module_name` is a folder inside some
        folder on the python sys.path, for example, sys.path as `C:/`, and
        you are inside the folder `C:/Path With Spaces` on the file 
        `C:/Path With Spaces/main.py` and want to re-import some files on
        the folder `C:/Path With Spaces/tests`

        @param full_module_name   the relative full path to the module file
                                  you want to reload from a folder on the
                                  python `sys.path`
    """
    import imp
    import sys
    import importlib

    if full_module_name in sys.modules:
        module_object = sys.modules[full_module_name]
        module_object = imp.reload( module_object )

    else:
        importlib.import_module( full_module_name )

def run_tests():
    print( "\n\n" )
    reload_module( "Path With Spaces.tests.semantic_linefeed_unit_tests" )
    reload_module( "Path With Spaces.tests.semantic_linefeed_manual_tests" )

    from .tests import semantic_linefeed_unit_tests
    from .tests import semantic_linefeed_manual_tests

    semantic_linefeed_unit_tests.run_unit_tests()
    semantic_linefeed_manual_tests.run_manual_tests()

if __name__ == "__main__":
    run_tests()

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.3Interpreter).

użytkownik
źródło
-1

Innym sposobem może być zaimportowanie modułu do funkcji. W ten sposób po zakończeniu funkcji moduł zostanie wyrzucony śmieci.

hackbot89
źródło
4
Moduł nigdy nie będzie zbierał śmieci, ponieważ globalne odwołanie jest przechowywane przynajmniej w sys.modules.
Wszyscy pracownicy są niezbędni