Как выгрузить (перезагрузить) модуль?

797

У меня есть долго работающий сервер Python, и я хотел бы иметь возможность обновить службу без перезапуска сервера. Какой лучший способ сделать это?

if foo.py has changed:
    unimport foo  <-- How do I do this?
    import foo
    myfoo = foo.Foo()
Марк Харрисон
источник
53
Подсказка: «импорт» не означает «загрузка», это означает «загрузить, если еще не загружен, а затем импортировать в пространство имен».
Кос
3
вопрос не должен включать «разгрузку», поскольку это пока невозможно в python - перезагрузка, однако, известная парадигма, на которую дан ответ ниже
robertmoggach
У меня была такая же проблема при использовании динамического модуля в приложении py2exe. Поскольку py2exe всегда сохранял байт-код в zip-каталоге, перезагрузка не работала. Но я нашел рабочее решение, используя модуль import_file. Теперь мое приложение работает нормально.
Притам Пан
2
Что если вы хотите «разгрузить», потому что в коде используется попытка удалить файл .pyc?
темный взгляд

Ответы:

795

Вы можете перезагрузить модуль, когда он уже был импортирован, используя reloadвстроенную функцию (только Python 3.4+) :

from importlib import reload  
import foo

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

В Python 3 reloadбыл перенесен в impмодуль. В 3.4 impбыл объявлен устаревшим в пользу importlib, и reloadбыл добавлен к последнему. При нацеливании на 3 или более позднюю версию, либо обращайтесь к соответствующему модулю при вызове, reloadлибо импортируйте его.

Я думаю, что это то, что вы хотите. Веб-серверы, такие как сервер разработки Django, используют это для того, чтобы вы могли видеть последствия изменений вашего кода без перезапуска самого процесса сервера.

Цитировать из документов:

Код модулей Python перекомпилируется, и код уровня модуля повторно выполняется, определяя новый набор объектов, которые связаны с именами в словаре модуля. Функция init модулей расширения не вызывается во второй раз. Как и со всеми другими объектами в Python, старые объекты восстанавливаются только после того, как их число ссылок упадет до нуля. Имена в пространстве имен модуля обновляются, чтобы указывать на любые новые или измененные объекты. Другие ссылки на старые объекты (например, имена, внешние по отношению к модулю) не привязываются к новым объектам и должны обновляться в каждом пространстве имен, где они встречаются, если это необходимо.

Как вы отметили в своем вопросе, вам придется реконструировать Fooобъекты, если Fooкласс находится в fooмодуле.

cdleary
источник
10
фактически, сервер django dev перезапускается сам, когда вы меняете файл .. (он перезагружает сервер, а не просто перезагружает модуль)
hasen
25
откуда эта функция is_changed? я не вижу документации по нему, и он не работает в моей среде Python 3.1.3, а также не работает в 2.6.4.
Джедмао
5
без слов, Django не может просто использовать перезагрузку: pyunit.sourceforge.net/notes/reloading.html
raylu
4
Перезагрузка недостаточна для модулей с зависимостями. См. Bobince ниже: stackoverflow.com/a/438845/456878 . Это укусило меня раньше и потратило целых 10 минут.
Даг Брэдшоу
5
@jedmao @JamesDraper Я почти уверен, что эта is_changedфункция - произвольная функция, которую вы должны написать; это не встроенный. Например, он может открыть файл, соответствующий импортируемому модулю, и сравнить его с кэшированной версией, чтобы увидеть, изменился ли он.
Джеймс Мчуг
252

В Python 3.0–3.3 вы бы использовали: imp.reload(module)

BDFL уже ответил на этот вопрос.

Тем не менее, impбыл объявлен устаревшим в 3.4, в пользуimportlib (спасибо @Stefan! ).

Я думаю , поэтому, вы бы сейчас использовали importlib.reload(module), хотя я не уверен.

Пол Д. Уэйт
источник
23
Серьезный новичок благодарен за изучение критических нюансов между Python 2 и 3.
Smandoli
24
действительно ли imp.reload (imp)?
Лоик Фор-Лакруа
2
@ LoïcFaure-Lacroix так же reload(__builtins__)действует в 2.x
JBernardo
1
@Tarrasch: это модуль Python, который вы хотите перезагрузить, как в примере в вопросе.
Пол Д. Уэйт
3
@ LoïcFaure-Lacroix да, имп может перезагрузить себя.
Девин Кольер Джонсон
93

Может быть особенно трудно удалить модуль, если он не является чистым Python.

Вот некоторая информация из: Как мне действительно удалить импортированный модуль?

Вы можете использовать sys.getrefcount (), чтобы узнать фактическое количество ссылок.

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

Числа больше 3 указывают на то, что будет трудно избавиться от модуля. Доморощенный «пустой» (не содержащий ничего) модуль должен собираться после

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

третья ссылка - это артефакт функции getrefcount ().

Грегг Линд
источник
4
Я только что обнаружил, что если модуль является частью пакета, вы должны также удалить его там:setattr(package, "empty", None)
u0b34a0f6ae
6
Это правильное решение, особенно если у вас есть пакет с вложенными модулями. reload()перезагружает только самый верхний модуль, и все, что находится внутри него, не будет перезагружено, если вы сначала не удалите его из sys.modules.
Cerin
73

reload(module), но только если он полностью автономен. Если что-то еще имеет ссылку на модуль (или какой-либо объект, принадлежащий модулю), то вы получите тонкие и любопытные ошибки, вызванные старым кодом, зависшим дольше, чем вы ожидали, и такими вещами, как isinstanceне работа в разных версиях тот же код

Если у вас есть односторонние зависимости, вы также должны перезагрузить все модули, которые зависят от перезагруженного модуля, чтобы избавиться от всех ссылок на старый код. А затем перезагрузите модули, которые зависят от загруженных модулей, рекурсивно.

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

Единственный способ сделать это в этом случае - взломать sys.modules, что не поддерживается. Вам нужно будет пройти и удалить каждую sys.modulesзапись, которую вы хотите перезагрузить при следующем импорте, а также удалить записи, значения которых относятся Noneк проблеме реализации, связанной с кэшированием неудачных относительных импортов. Это не очень приятно, но пока у вас есть полностью автономный набор зависимостей, который не оставляет ссылок вне своей кодовой базы, это работоспособно.

Вероятно, лучше перезагрузить сервер. :-)

bobince
источник
1
Разве dreload специально для этого сценария?
Джош
@Josh: нет, он предназначен для перезагрузки дерева пакетов, и даже тогда он работает только до тех пор, пока пакет не имеет внешних / циклических зависимостей.
Бобинц
1
Можете ли вы уточнить деталь со Noneзначениями, потому что я работаю именно с этой проблемой: я удаляю элементы из sys.modulesи после повторного импорта некоторые импортированные зависимости None.
Шламар
@shclamar: см. stackoverflow.com/questions/1958417/… (и ссылки оттуда) для фона. Мне неясно (даже глядя на код import.c), как Noneзаписи смогли вернуться через механизм импорта, когда «реальные» записи были удалены, и я не могу этого добиться в 2.7; в будущем, конечно, это больше не проблема, поскольку неявный относительный импорт исчез. А пока удаляем все записи сNone значением, похоже, исправляет это.
2013 года
1
@Eliethesaiyan: ты имеешь в виду reloadфункцию? Он встроен, вам не нужно импортировать какую-либо библиотеку.
бобинц
63
if 'myModule' in sys.modules:  
    del sys.modules["myModule"]
Kumaresan
источник
3
+1. Моя цель состояла в том, чтобы провести тесты носа в питоне. После того, как я загрузил модуль и переименовал некоторые функции, старые имена остались при вызове nose.run(), даже послеreload(my_module) %run my_module
Peter D
5
Если ваш модуль импортирует свои собственные подмодули, возможно, вам придется удалить их. Нечто подобное [del(sys.modules[mod] for mod in sys.modules.keys() if mod.startswith('myModule.')].
drevicko
Я не думаю, что это выгружает модуль. На Python 3.8: import sys; import json; del sys.modules['json']; print(json.dumps([1]))и модуль json все еще работает, хотя его больше нет в sys.modules.
Сеперман
60

Для Python 2 используйте встроенную функцию reload () :

reload(module)

Для Python 2 и 3.2–3.3 используйте reload из модуля imp :

import imp
imp.reload(module)

Но imp не рекомендуется с версии 3.4 в пользу importlib , поэтому используйте:

import importlib
importlib.reload(module)

или

from importlib import reload
reload(module)
goetzc
источник
2
чтобы справиться с любым из этих случаев: from six import reload_module(надо pip install sixсначала конечно)
Anentropic
@Anentropic: это хороший совет, чтобы рекомендовать использовать шесть пакетов, но синтаксис: from six.moves import reload_module( doc )
x0s
23

Следующий код обеспечивает совместимость с Python 2/3:

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

Вы можете использовать его как reload()в обеих версиях, что упрощает работу.

Мэтт Кларксон
источник
18

Принятый ответ не обрабатывает случай импорта X из Y. Этот код обрабатывает его, а также стандартный случай импорта:

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

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

Джозеф Гарвин
источник
Заметив проблему, globals () относится к модулю, в котором вы определяете эту функцию, поэтому, если вы определите ее в модуле, отличном от того, в котором вы ее вызываете, это не сработает.
Джозеф Гарвин
Для интерактивного, после >>> from X import Yперезагрузки сделать>>> __import__('X', fromlist='Y')
Боб Стейн
@ BobStein-VisiBone, есть ли способ заставить это работать когда fromlist='*'?
Майк C
Хороший вопрос, не знаю @MikeC. Кстати, я склонен прекратить почти все использование fromв операторах импорта. Просто откровенный import <package>и явный package.symbol в коде. Осознайте, что это не всегда возможно или желательно. (Вот одно исключение: из будущего импорта print_function.)
Боб Стейн
Майк C: что работает для меняfoo = reload(foo); from foo import *
Rampion
16

Это современный способ перезагрузки модуля:

from importlib import reload

Если вы хотите поддерживать версии Python старше 3.5, попробуйте это:

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+

Чтобы использовать его, запустите reload(MODULE), заменивMODULE на модуль, который вы хотите перезагрузить.

Например, reload(math)перезагрузит mathмодуль.

Ричи Бендалл
источник
4
Или просто сделай from importlib import reload. Тогда вы можете сделать reload(MODULE_NAME). Там нет необходимости для этой функции.
Pault
Я считаю, что modulereload(MODULE_NAME)это более очевидно, чем просто, reload(MODULE_NAME)и у него меньше шансов конфликтовать с другими функциями.
Ричи Бендалл
@RichieBendall Извините, но этот ответ совершенно неправильный. Функция reload () принимает объект модуля, а не имя модуля ... Прочитайте документы: docs.python.org/3/library/importlib.html#importlib.reload И я согласен с @ pault - это «как modulereload» излишне ,
mbdevpl
Я изменил свой ответ, чтобы отразить ваше мнение.
Ричи Бендалл
13

Если вы не на сервере, но разрабатываете и вам нужно часто перезагружать модуль, вот хороший совет.

Во-первых, убедитесь, что вы используете превосходную оболочку IPython из проекта Jupyter Notebook. После установки Jupyter вы можете запустить его ipython, илиjupyter console , или даже лучше jupyter qtconsole, что даст вам красивую раскрашенную консоль с дополнением кода в любой ОС.

Теперь в вашей оболочке введите:

%load_ext autoreload
%autoreload 2

Теперь каждый раз вы запускаете ваш скрипт, ваши модули будут перезагружаться.

Помимо 2, есть и другие варианты магии автозагрузки :

%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.
Невиш
источник
7

Для таких как я, которые хотят выгрузить все модули (при работе в интерпретаторе Python под Emacs ):

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

Больше информации в Перезагрузке модулей Python .

Питер Мортенсен
источник
На самом деле это не работает надежно (в 2.6), потому что не все в sys.modules.values()модуле. Например: >>> type (sys.modules.values ​​() [1]) <class 'email.LazyImporter'> Так что, если я пытаюсь запустить этот код, он падает (я знаю, что это не практическое решение, просто указывая на это).
Фрэнсис Дэйви
Это даже не работает в более ранних питонах - как написано. Я должен был исключить некоторые имена. Я обновлю пост, когда перенесу этот код на свой новый компьютер.
2
Прекрасно работает в Python 2.7 после некоторых модификаций:if mod and mod.__name__ != "__main__": imp.reload(mod)
Czarek Tomczak
2
Это хорошо работает для меня: импорт imp [reload (m) для m в sys.modules.values ​​(), если m и не " " в имени m .__, а не imp.is_builtin (m .__ name__)]
Патрик Вольф
5

Enthought Traits имеет модуль, который довольно хорошо работает для этого. https://traits.readthedocs.org/en/4.3.0/_modules/traits/util/refresh.html

Он перезагрузит любой модуль, который был изменен, и обновит другие модули и экземпляры, которые его используют. Это не работает большую часть времени с__very_private__ методами и может подавить наследование классов, но это избавляет меня от сумасшедших затрат времени от необходимости перезапускать хост-приложение при написании PyQt-приложений или вещи, которые запускаются внутри таких программ, как Maya или Nuke. Это не работает, может быть, 20-30% времени, но все равно невероятно полезно.

Пакет Enthought не перезагружает файлы в тот момент, когда они меняются - вы должны называть это явно - но это не должно быть так сложно реализовать, если вам это действительно нужно

flipthefrog
источник
5

Те, кто использует Python 3 и перезагрузить из importlib.

Если у вас есть проблемы, такие как кажется, что модуль не перезагружается ... Это потому, что ему нужно некоторое время для перекомпиляции pyc (до 60 секунд). Я пишу этот совет только для того, чтобы вы знали, если у вас возникли проблемы такого рода.

PythonMan
источник
3

Другой вариант. Обратите внимание, что Python по умолчанию importlib.reloadпросто повторно импортирует библиотеку, переданную в качестве аргумента. Он не перезагрузит библиотеки, которые импортирует ваша библиотека. Если вы изменили много файлов и у вас есть несколько сложный пакет для импорта, вы должны выполнить глубокую перезагрузку .

Если у вас установлен IPython или Jupyter , вы можете использовать функцию для глубокой перезагрузки всех библиотек:

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

Если у вас нет Jupyter, установите его с помощью этой команды в вашей оболочке:

pip3 install jupyter
Невиш
источник
И этот Ipython dreload и reload () из importlib действительно жалуются reload() argument must be module. Я использую пользовательскую функцию импорта и, похоже, не работает. Использование встроенных модулей работает. :-( перезагружать iPython - пустая трата времени для каждого небольшого изменения, которое я внес в свой код ...
m3nda
2

Изменить (Ответ V2)

Предыдущее решение хорошо просто для получения информации о сбросе, но оно не изменит все ссылки (больше, чем reloadтребуется, но меньше). Чтобы на самом деле установить все ссылки, я должен был пойти в сборщик мусора и переписать ссылки там. Теперь это работает как шарм!

Обратите внимание, что это не будет работать, если GC выключен или если загружаются данные, которые не контролируются GC. Если вы не хотите связываться с GC, вам может быть достаточно оригинального ответа.

Новый код:

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)

Оригинальный ответ

Как написано в ответе @ bobince, если в другом модуле уже есть ссылка на этот модуль (особенно если он был импортирован с asключевым словом like import numpy as np), этот экземпляр не будет перезаписан.

Это оказалось весьма проблематично для меня , когда применение тестов , которые требуют «чистого листа» состояние модулей конфигурации, поэтому я написал функцию с именем , reset_moduleкоторый использует importlib«ы reloadфункции и рекурсивно перезаписывает все атрибуты Заявленная модуля. Он был протестирован с версией Python 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

Примечание: используйте с осторожностью! Использование их в не периферийных модулях (например, в модулях, которые определяют классы, используемые извне) может привести к внутренним проблемам в Python (таким как проблемы выбора / отмены выбора).

EZLearner
источник
1

для меня для случая Abaqus это так, как это работает. Представьте, что ваш файл 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'])
Мэтт С
источник
Этот ответ является прямой копией здесь: ebanshi.cc/questions/1942/…
SiHa
0

У меня было много проблем при попытке перезагрузить что-то внутри Sublime Text, но, наконец, я смог написать эту утилиту для перезагрузки модулей в Sublime Text на основе кода, sublime_plugin.pyиспользуемого для перезагрузки модулей.

Это ниже позволяет вам перезагрузить модули из путей с пробелами в их именах, а затем после перезагрузки вы можете просто импортировать как обычно.

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

Если вы запускаете в первый раз, это должно загрузить модуль, но если позже вы сможете снова запустить метод / функцию, run_tests()он перезагрузит тестовые файлы. С Sublime Text ( Python 3.3.6) это часто происходит, потому что его интерпретатор никогда не закрывается (если вы не перезапустите Sublime Text, то есть Python3.3интерпретатор).

пользователь
источник
-1

Другим способом может быть импорт модуля в функцию. Таким образом, когда функция завершает работу, модуль получает мусор.

hackbot89
источник
4
Модуль никогда не будет собирать мусор, потому что глобальная ссылка хранится, по крайней мере, в sys.modules.
Все работники необходимы